<commit_before>package models

import (
    "fmt"
    "encoding/json"
    "strings"
    "time"
)

/*
GenericFile contains information about a file that makes up
part (or all) of an IntellectualObject.

IntellectualObject is the object to which the file belongs.

Format is typically a mime-type, such as "application/xml",
that describes the file format.

URI describes the location of the object (in APTrust?).

Size is the size of the object, in bytes.

FileCreated is the date and time at which the file was created
by the depositor.

FileModified is the data and time at which the object was last
modified (in APTrust, or at the institution that owns it?).

CreatedAt and UpdatedAt are Rails timestamps describing when
this GenericFile records was created and last updated.

FileCreated and FileModified should be ISO8601 DateTime strings,
such as:
1994-11-05T08:15:30-05:00     (Local Time)
1994-11-05T08:15:30Z          (UTC)
*/
type GenericFile struct {
    // Pharos fields.

    // The Rails/Database id for this generic file.
    // If the Id is non-zero, it's been recorded in Pharos.
    Id                           int            `json:"id"`

    // The human-readable identifier for this file. It consists of
    // the object name, followed by a slash, followed by the path
    // of the file within the bag. E.g. "virginia.edu/bag001/data/file1.pdf"
    Identifier                   string         `json:"identifier"`

    // The id of the IntellectualObject to which this file belongs.
    IntellectualObjectId         int            `json:"intellectual_object_id"`

    // The identifier of the intellectual object to which this file belongs.
    IntellectualObjectIdentifier string         `json:"intellectual_object_identifier"`

    // The file's mime type. E.g. "application/xml"
    FileFormat                   string         `json:"file_format"`

    // The location of this file in our primary s3 long-term storage bucket.
    URI                          string         `json:"uri"`

    // The size of the file, in bytes.
    Size                         int64          `json:"size"`

    // The date this file was created by the depositor. This date comes from
    // the file record in the tarred bag.
    FileCreated                  time.Time      `json:"file_created"`

    // The date this file was last modified by the depository. This date comes
    // from the file record in the tarred bag.
    FileModified                 time.Time      `json:"file_modified"`

    // A timestamp indicating when this GenericFile record was created in
    // our repository.
    CreatedAt                    time.Time      `json:"created_at"`

    // A timestamp indicating when this GenericFile record was last updated in
    // our repository.
    UpdatedAt                    time.Time      `json:"updated_at"`

    // A list of checksums for this file.
    Checksums                    []*Checksum    `json:"checksums"`

    // A list of PREMIS events for this file.
    PremisEvents                 []*PremisEvent `json:"premis_events"`

    // ----------------------------------------------------
    // The fields below are for internal housekeeping
    // during the ingest process. We don't send this data
    // to Pharos, and none of the Ingest fields will be
    // populated on GenericFile objects retrieved from
    // Pharos.
    // ----------------------------------------------------

    // IngestFileType can be one of the types defined in constants.
    // PAYLOAD_FILE, PAYLOAD_MANIFEST, TAG_MANIFEST, TAG_FILE
    IngestFileType               string         `json:"ingest_file_type,omitempty"`

    // IngestLocalPath is the absolute path to this file on local disk.
    // It may be empty if we're working with a tar file.
    IngestLocalPath              string         `json:"ingest_local_path,omitempty"`

    // IngestManifestMd5 is the md5 checksum of this file, as reported
    // in the bag's manifest-md5.txt file. This may be empty if there
    // was no md5 checksum file, or if this generic file wasn't listed
    // in the md5 manifest.
    IngestManifestMd5            string         `json:"ingest_manifest_md5,omitempty"`

    // The md5 checksum we calculated at ingest from the actual file.
    IngestMd5                    string         `json:"ingest_md5,omitempty"`

    // DateTime we calculated the md5 digest from local file.
    IngestMd5GeneratedAt         time.Time      `json:"ingest_md5_generated_at,omitempty"`

    // DateTime we verified that our md5 checksum matches what's in the manifest.
    IngestMd5VerifiedAt          time.Time      `json:"ingest_md5_verified_at,omitempty"`

    // The sha256 checksum for this file, as reported in the payload manifest.
    // This may be empty if the bag had no sha256 manifest, or if this file
    // was not listed in the manifest.
    IngestManifestSha256         string         `json:"ingest_manifest_sha256,omitempty"`

    // The sha256 checksum we calculated when we read the actual file.
    IngestSha256                 string         `json:"ingest_sha_256,omitempty"`

    // Timestamp of when we calculated the sha256 checksum.
    IngestSha256GeneratedAt      time.Time      `json:"ingest_sha_256_generated_at,omitempty"`

    // Timestamp of when we verified that the sha256 checksum we calculated
    // matches what's in the manifest.
    IngestSha256VerifiedAt       time.Time      `json:"ingest_sha_256_verified_at,omitempty"`

    // The UUID assigned to this file. This will be its S3 key when we store it.
    IngestUUID                   string         `json:"ingest_uuid,omitempty"`

    // Timestamp of when we generated the UUID for this file. Needed to create
    // the identifier assignment PREMIS event.
    IngestUUIDGeneratedAt        time.Time      `json:"ingest_uuid_generated_at,omitempty"`

    // Where this file is stored in S3.
    IngestStorageURL             string         `json:"ingest_storage_url,omitempty"`

    // Timestamp indicating when this file was stored in S3.
    IngestStoredAt               time.Time      `json:"ingest_stored_at,omitempty"`

    // Where this file is stored in Glacier.
    IngestReplicationURL         string         `json:"ingest_replication_url,omitempty"`

    // Timestamp indicating when this file was stored in Glacier.
    IngestReplicatedAt           time.Time      `json:"ingest_replicated_at,omitempty"`

    // If true, a previous version of this same file exists in S3/Glacier.
    IngestPreviousVersionExists  bool           `json:"ingest_previous_version_exists,omitempty"`

    // If true, this file needs to be saved to S3.
    IngestNeedsSave              bool           `json:"ingest_needs_save,omitempty"`

    // Error that occurred during ingest. If empty, there was no error.
    IngestErrorMessage           string         `json:"ingesterror_message,omitempty"`

    // File User Id (unreliable)
    IngestFileUid                int            `json:"ingest_file_uid,omitempty"`

    // File Group Id (unreliable)
    IngestFileGid                int            `json:"ingest_file_gid,omitempty"`

    // File User Name (unreliable)
    IngestFileUname              string         `json:"ingest_file_uname,omitempty"`

    // File Group Name (unreliable)
    IngestFileGname              string         `json:"ingest_file_gname,omitempty"`

    // File Mode/Permissions (unreliable)
    IngestFileMode               int64          `json:"ingest_file_mode,omitempty"`

    // ----------------------------------------------------
    // The fields below are for internal housekeeping
    // during the restoration, fixity checking, and DPN
    // packaging processes, during which Exchange services
    // download files from long-term storage to run fixity
    // or to rebuild a bag from its component files. The
    // Fetch fields are not saved in Pharos,
    // and GenericFiles retrieved from Pharos will not have
    // Fetch data. Exchange populates those fields
    // as necessary, according to the work it's doing.
    // ----------------------------------------------------

    // FetchLocalPath is the path on the local file system where we
    // saved this file after retrieving it from S3 long-term storage.
    // We only set this when we fetch files to be restored or to be
    // packaged into a DPN bag. When we fetch files for fixity checking,
    // we stream them to /dev/null, because we're only interested in
    // computing a checksum.
    FetchLocalPath              string         `json:"fetch_local_path,omitempty"`

    // FetchMd5Value is the md5 digest we computed on the file we pulled
    // down from S3. This is supposed to match the file's known md5 fixity
    // value.
    FetchMd5Value               string         `json:"fetch_md5_value,omitempty"`

    // FetchSha256Value is the sha256 digest we computed on the file we
    // pulled down from S3. This should match the known sha256 digest.
    FetchSha256Value            string         `json:"fetch_sha256_value,omitempty"`

    // FetchErrorMessage describes any error that occured during the
    // fetch process, including network errors, object not found, no disk
    // space, fixity mismatches, etc.
    FetchErrorMessage           string         `json:"fetch_error_message,omitempty"`
}

func NewGenericFile() (*GenericFile) {
    return &GenericFile{
        Checksums: make([]*Checksum, 0),
        PremisEvents: make([]*PremisEvent, 0),
        IngestPreviousVersionExists: false,
        IngestNeedsSave: true,
    }
}

// Serializes a version of GenericFile that Fluctus will accept as post/put input.
// Note that we don't serialize the id or any of our internal housekeeping info.
func (gf *GenericFile) SerializeForPharos() ([]byte, error) {
    // We have to create a temporary structure to prevent json.Marshal
    // from serializing Size (int64) with scientific notation.
    // Without this step, Size will be serialized as something like
    // 2.706525e+06, which is not valid JSON.
    temp := struct{
        Identifier                   string         `json:"identifier"`
        IntellectualObjectId         int            `json:"intellectual_object_id"`
        IntellectualObjectIdentifier string         `json:"intellectual_object_identifier"`
        FileFormat                   string         `json:"file_format"`
        URI                          string         `json:"uri"`
        Size                         int64          `json:"size"`
        FileCreated                  time.Time      `json:"file_created"`
        FileModified                 time.Time      `json:"file_modified"`
        CreatedAt                    time.Time      `json:"created_at"`
        UpdatedAt                    time.Time      `json:"updated_at"`
        Checksums                    []*Checksum    `json:"checksums"`
    } {
        Identifier:                     gf.Identifier,
        IntellectualObjectId:           gf.IntellectualObjectId,
        IntellectualObjectIdentifier:   gf.IntellectualObjectIdentifier,
        FileFormat:                     gf.FileFormat,
        URI:                            gf.URI,
        Size:                           gf.Size,
        FileCreated:                    gf.FileCreated,
        FileModified:                   gf.FileModified,
        Checksums:                      gf.Checksums,
    }
    return json.Marshal(temp)
}

// Returns the original path of the file within the original bag.
// This is just the identifier minus the institution id and bag name.
// For example, if the identifier is "uc.edu/cin.675812/data/object.properties",
// this returns "data/object.properties"
func (gf *GenericFile) OriginalPath() (string) {
    return strings.Replace(gf.Identifier, gf.IntellectualObjectIdentifier + "/", "", 1)
}

// Returns the name of the institution that owns this file.
func (gf *GenericFile) InstitutionIdentifier() (string, error) {
    parts := strings.Split(gf.Identifier, "/")
    if len(parts) < 2 {
        return "", fmt.Errorf("GenericFile identifier '%s' is not valid", gf.Identifier)
    }
    return parts[0], nil
}

// Returns the checksum digest for the given algorithm for this file.
func (gf *GenericFile) GetChecksum(algorithm string) (*Checksum) {
    for _, cs := range gf.Checksums {
        if cs != nil && cs.Algorithm == algorithm {
            return cs
        }
    }
    return nil
}

// Returns events of the specified type
func (gf *GenericFile) FindEventsByType(eventType string) ([]PremisEvent) {
    events := make([]PremisEvent, 0)
    for _, event := range gf.PremisEvents {
        if event != nil && event.EventType == eventType {
            events = append(events, *event)
        }
    }
    return events
}

// Returns the name of this file in the preservation storage bucket
// (that should be a UUID), or an error if the GenericFile does not
// have a valid preservation storage URL.
func (gf *GenericFile) PreservationStorageFileName() (string, error) {
    if strings.Index(gf.URI, "/") < 0 {
        return "", fmt.Errorf("Cannot get preservation storage file name because GenericFile has an invalid URI")
    }
    parts := strings.Split(gf.URI, "/")
    return parts[len(parts) - 1], nil
}
<commit_msg>Don't serialize uri if it's blank<commit_after>package models

import (
	"fmt"
	"encoding/json"
	"strings"
	"time"
)

/*
GenericFile contains information about a file that makes up
part (or all) of an IntellectualObject.

IntellectualObject is the object to which the file belongs.

Format is typically a mime-type, such as "application/xml",
that describes the file format.

URI describes the location of the object (in APTrust?).

Size is the size of the object, in bytes.

FileCreated is the date and time at which the file was created
by the depositor.

FileModified is the data and time at which the object was last
modified (in APTrust, or at the institution that owns it?).

CreatedAt and UpdatedAt are Rails timestamps describing when
this GenericFile records was created and last updated.

FileCreated and FileModified should be ISO8601 DateTime strings,
such as:
1994-11-05T08:15:30-05:00     (Local Time)
1994-11-05T08:15:30Z          (UTC)
*/
type GenericFile struct {
	// Pharos fields.

	// The Rails/Database id for this generic file.
	// If the Id is non-zero, it's been recorded in Pharos.
	Id                           int            `json:"id"`

	// The human-readable identifier for this file. It consists of
	// the object name, followed by a slash, followed by the path
	// of the file within the bag. E.g. "virginia.edu/bag001/data/file1.pdf"
	Identifier                   string         `json:"identifier"`

	// The id of the IntellectualObject to which this file belongs.
	IntellectualObjectId         int            `json:"intellectual_object_id"`

	// The identifier of the intellectual object to which this file belongs.
	IntellectualObjectIdentifier string         `json:"intellectual_object_identifier"`

	// The file's mime type. E.g. "application/xml"
	FileFormat                   string         `json:"file_format"`

	// The location of this file in our primary s3 long-term storage bucket.
	URI                          string         `json:"uri,omitempty"`

	// The size of the file, in bytes.
	Size                         int64          `json:"size"`

	// The date this file was created by the depositor. This date comes from
	// the file record in the tarred bag.
	FileCreated                  time.Time      `json:"file_created"`

	// The date this file was last modified by the depository. This date comes
	// from the file record in the tarred bag.
	FileModified                 time.Time      `json:"file_modified"`

	// A timestamp indicating when this GenericFile record was created in
	// our repository.
	CreatedAt                    time.Time      `json:"created_at"`

	// A timestamp indicating when this GenericFile record was last updated in
	// our repository.
	UpdatedAt                    time.Time      `json:"updated_at"`

	// A list of checksums for this file.
	Checksums                    []*Checksum    `json:"checksums"`

	// A list of PREMIS events for this file.
	PremisEvents                 []*PremisEvent `json:"premis_events"`

	// ----------------------------------------------------
	// The fields below are for internal housekeeping
	// during the ingest process. We don't send this data
	// to Pharos, and none of the Ingest fields will be
	// populated on GenericFile objects retrieved from
	// Pharos.
	// ----------------------------------------------------

	// IngestFileType can be one of the types defined in constants.
	// PAYLOAD_FILE, PAYLOAD_MANIFEST, TAG_MANIFEST, TAG_FILE
	IngestFileType               string         `json:"ingest_file_type,omitempty"`

	// IngestLocalPath is the absolute path to this file on local disk.
	// It may be empty if we're working with a tar file.
	IngestLocalPath              string         `json:"ingest_local_path,omitempty"`

	// IngestManifestMd5 is the md5 checksum of this file, as reported
	// in the bag's manifest-md5.txt file. This may be empty if there
	// was no md5 checksum file, or if this generic file wasn't listed
	// in the md5 manifest.
	IngestManifestMd5            string         `json:"ingest_manifest_md5,omitempty"`

	// The md5 checksum we calculated at ingest from the actual file.
	IngestMd5                    string         `json:"ingest_md5,omitempty"`

	// DateTime we calculated the md5 digest from local file.
	IngestMd5GeneratedAt         time.Time      `json:"ingest_md5_generated_at,omitempty"`

	// DateTime we verified that our md5 checksum matches what's in the manifest.
	IngestMd5VerifiedAt          time.Time      `json:"ingest_md5_verified_at,omitempty"`

	// The sha256 checksum for this file, as reported in the payload manifest.
	// This may be empty if the bag had no sha256 manifest, or if this file
	// was not listed in the manifest.
	IngestManifestSha256         string         `json:"ingest_manifest_sha256,omitempty"`

	// The sha256 checksum we calculated when we read the actual file.
	IngestSha256                 string         `json:"ingest_sha_256,omitempty"`

	// Timestamp of when we calculated the sha256 checksum.
	IngestSha256GeneratedAt      time.Time      `json:"ingest_sha_256_generated_at,omitempty"`

	// Timestamp of when we verified that the sha256 checksum we calculated
	// matches what's in the manifest.
	IngestSha256VerifiedAt       time.Time      `json:"ingest_sha_256_verified_at,omitempty"`

	// The UUID assigned to this file. This will be its S3 key when we store it.
	IngestUUID                   string         `json:"ingest_uuid,omitempty"`

	// Timestamp of when we generated the UUID for this file. Needed to create
	// the identifier assignment PREMIS event.
	IngestUUIDGeneratedAt        time.Time      `json:"ingest_uuid_generated_at,omitempty"`

	// Where this file is stored in S3.
	IngestStorageURL             string         `json:"ingest_storage_url,omitempty"`

	// Timestamp indicating when this file was stored in S3.
	IngestStoredAt               time.Time      `json:"ingest_stored_at,omitempty"`

	// Where this file is stored in Glacier.
	IngestReplicationURL         string         `json:"ingest_replication_url,omitempty"`

	// Timestamp indicating when this file was stored in Glacier.
	IngestReplicatedAt           time.Time      `json:"ingest_replicated_at,omitempty"`

	// If true, a previous version of this same file exists in S3/Glacier.
	IngestPreviousVersionExists  bool           `json:"ingest_previous_version_exists,omitempty"`

	// If true, this file needs to be saved to S3.
	IngestNeedsSave              bool           `json:"ingest_needs_save,omitempty"`

	// Error that occurred during ingest. If empty, there was no error.
	IngestErrorMessage           string         `json:"ingesterror_message,omitempty"`

	// File User Id (unreliable)
	IngestFileUid                int            `json:"ingest_file_uid,omitempty"`

	// File Group Id (unreliable)
	IngestFileGid                int            `json:"ingest_file_gid,omitempty"`

	// File User Name (unreliable)
	IngestFileUname              string         `json:"ingest_file_uname,omitempty"`

	// File Group Name (unreliable)
	IngestFileGname              string         `json:"ingest_file_gname,omitempty"`

	// File Mode/Permissions (unreliable)
	IngestFileMode               int64          `json:"ingest_file_mode,omitempty"`

	// ----------------------------------------------------
	// The fields below are for internal housekeeping
	// during the restoration, fixity checking, and DPN
	// packaging processes, during which Exchange services
	// download files from long-term storage to run fixity
	// or to rebuild a bag from its component files. The
	// Fetch fields are not saved in Pharos,
	// and GenericFiles retrieved from Pharos will not have
	// Fetch data. Exchange populates those fields
	// as necessary, according to the work it's doing.
	// ----------------------------------------------------

	// FetchLocalPath is the path on the local file system where we
	// saved this file after retrieving it from S3 long-term storage.
	// We only set this when we fetch files to be restored or to be
	// packaged into a DPN bag. When we fetch files for fixity checking,
	// we stream them to /dev/null, because we're only interested in
	// computing a checksum.
	FetchLocalPath              string         `json:"fetch_local_path,omitempty"`

	// FetchMd5Value is the md5 digest we computed on the file we pulled
	// down from S3. This is supposed to match the file's known md5 fixity
	// value.
	FetchMd5Value               string         `json:"fetch_md5_value,omitempty"`

	// FetchSha256Value is the sha256 digest we computed on the file we
	// pulled down from S3. This should match the known sha256 digest.
	FetchSha256Value            string         `json:"fetch_sha256_value,omitempty"`

	// FetchErrorMessage describes any error that occured during the
	// fetch process, including network errors, object not found, no disk
	// space, fixity mismatches, etc.
	FetchErrorMessage           string         `json:"fetch_error_message,omitempty"`
}

func NewGenericFile() (*GenericFile) {
	return &GenericFile{
		Checksums: make([]*Checksum, 0),
		PremisEvents: make([]*PremisEvent, 0),
		IngestPreviousVersionExists: false,
		IngestNeedsSave: true,
	}
}

// Serializes a version of GenericFile that Fluctus will accept as post/put input.
// Note that we don't serialize the id or any of our internal housekeeping info.
func (gf *GenericFile) SerializeForPharos() ([]byte, error) {
	// We have to create a temporary structure to prevent json.Marshal
	// from serializing Size (int64) with scientific notation.
	// Without this step, Size will be serialized as something like
	// 2.706525e+06, which is not valid JSON.
	temp := struct{
		Identifier                   string         `json:"identifier"`
		IntellectualObjectId         int            `json:"intellectual_object_id"`
		IntellectualObjectIdentifier string         `json:"intellectual_object_identifier"`
		FileFormat                   string         `json:"file_format"`
		URI                          string         `json:"uri"`
		Size                         int64          `json:"size"`
		FileCreated                  time.Time      `json:"file_created"`
		FileModified                 time.Time      `json:"file_modified"`
		CreatedAt                    time.Time      `json:"created_at"`
		UpdatedAt                    time.Time      `json:"updated_at"`
		Checksums                    []*Checksum    `json:"checksums"`
	} {
		Identifier:                     gf.Identifier,
		IntellectualObjectId:           gf.IntellectualObjectId,
		IntellectualObjectIdentifier:   gf.IntellectualObjectIdentifier,
		FileFormat:                     gf.FileFormat,
		URI:                            gf.URI,
		Size:                           gf.Size,
		FileCreated:                    gf.FileCreated,
		FileModified:                   gf.FileModified,
		Checksums:                      gf.Checksums,
	}
	return json.Marshal(temp)
}

// Returns the original path of the file within the original bag.
// This is just the identifier minus the institution id and bag name.
// For example, if the identifier is "uc.edu/cin.675812/data/object.properties",
// this returns "data/object.properties"
func (gf *GenericFile) OriginalPath() (string) {
	return strings.Replace(gf.Identifier, gf.IntellectualObjectIdentifier + "/", "", 1)
}

// Returns the name of the institution that owns this file.
func (gf *GenericFile) InstitutionIdentifier() (string, error) {
	parts := strings.Split(gf.Identifier, "/")
	if len(parts) < 2 {
		return "", fmt.Errorf("GenericFile identifier '%s' is not valid", gf.Identifier)
	}
	return parts[0], nil
}

// Returns the checksum digest for the given algorithm for this file.
func (gf *GenericFile) GetChecksum(algorithm string) (*Checksum) {
	for _, cs := range gf.Checksums {
		if cs != nil && cs.Algorithm == algorithm {
			return cs
		}
	}
	return nil
}

// Returns events of the specified type
func (gf *GenericFile) FindEventsByType(eventType string) ([]PremisEvent) {
	events := make([]PremisEvent, 0)
	for _, event := range gf.PremisEvents {
		if event != nil && event.EventType == eventType {
			events = append(events, *event)
		}
	}
	return events
}

// Returns the name of this file in the preservation storage bucket
// (that should be a UUID), or an error if the GenericFile does not
// have a valid preservation storage URL.
func (gf *GenericFile) PreservationStorageFileName() (string, error) {
	if strings.Index(gf.URI, "/") < 0 {
		return "", fmt.Errorf("Cannot get preservation storage file name because GenericFile has an invalid URI")
	}
	parts := strings.Split(gf.URI, "/")
	return parts[len(parts) - 1], nil
}
<|endoftext|>


<commit_before>// Copyright 2015 bs authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package metric

import (
	"net/http"
	"os"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/fsouza/go-dockerclient/testing"
	"gopkg.in/check.v1"
)

type bogusContainer struct {
	config docker.Config
	state  docker.State
	name   string
}

func (s *S) TestRunner(c *check.C) {
	os.Unsetenv("CONTAINER_SELECTION_ENV")
	bogusContainers := s.buildContainers()
	dockerServer, conts := s.startDockerServer(bogusContainers, nil, c)
	defer dockerServer.Stop()
	s.prepareStats(dockerServer, conts)
	r := NewRunner(dockerServer.URL(), time.Second, "fake")
	err := r.Start()
	c.Assert(err, check.IsNil)
	r.Stop()
	cpuStat := make([]*fakeStat, 0)
	for i, stat := range fakeStatter.stats {
		if stat.key == "cpu_max" {
			cpuStat = append(cpuStat, &fakeStatter.stats[i])
		}
	}
	c.Assert(len(cpuStat), check.Equals, 2)
	expected := []*fakeStat{
		{
			container: "nonApp",
			image:     "tsuru/python",
			hostname:  conts[0].ID[:12],
			key:       "cpu_max",
			value:     float(250),
		},
		{
			container: "app",
			app:       "someapp",
			image:     "tsuru/python",
			hostname:  conts[1].ID[:12],
			process:   "myprocess",
			key:       "cpu_max",
			value:     float(250),
		},
	}
	if fakeStatter.stats[0].hostname != conts[0].ID[:12] {
		expected[0], expected[1] = expected[1], expected[0]
	}
	for i, stat := range cpuStat {
		c.Assert(stat, check.DeepEquals, expected[i])
	}
}

func (s *S) TestRunnerSelectionEnv(c *check.C) {
	os.Setenv("CONTAINER_SELECTION_ENV", "TSURU_APPNAME")
	defer os.Unsetenv("CONTAINER_SELECTION_ENV")
	bogusContainers := s.buildContainers()
	dockerServer, conts := s.startDockerServer(bogusContainers, nil, c)
	defer dockerServer.Stop()
	s.prepareStats(dockerServer, conts)
	r := NewRunner(dockerServer.URL(), time.Second, "fake")
	err := r.Start()
	c.Assert(err, check.IsNil)
	r.Stop()
	cpuStat := make([]*fakeStat, 0)
	for i, stat := range fakeStatter.stats {
		if stat.key == "cpu_max" {
			cpuStat = append(cpuStat, &fakeStatter.stats[i])
		}
	}
	c.Assert(len(cpuStat), check.Equals, 1)
	expected := []*fakeStat{
		{
			container: "app",
			app:       "someapp",
			image:     "tsuru/python",
			hostname:  conts[1].ID[:12],
			process:   "myprocess",
			key:       "cpu_max",
			value:     float(250),
		},
	}
	c.Assert(cpuStat[0], check.DeepEquals, expected[0])
}

func (s *S) startDockerServer(containers []bogusContainer, hook func(*http.Request), c *check.C) (*testing.DockerServer, []docker.Container) {
	server, err := testing.NewServer("127.0.0.1:0", nil, hook)
	c.Assert(err, check.IsNil)
	client, err := docker.NewClient(server.URL())
	c.Assert(err, check.IsNil)
	createdContainers := make([]docker.Container, len(containers))
	for i, bogus := range containers {
		pullOpts := docker.PullImageOptions{Repository: bogus.config.Image}
		err = client.PullImage(pullOpts, docker.AuthConfiguration{})
		c.Assert(err, check.IsNil)
		createOpts := docker.CreateContainerOptions{Name: bogus.name, Config: &bogus.config}
		container, err := client.CreateContainer(createOpts)
		c.Assert(err, check.IsNil)
		err = server.MutateContainer(container.ID, bogus.state)
		c.Assert(err, check.IsNil)
		createdContainers[i] = *container
	}
	return server, createdContainers
}

func (s *S) buildContainers() []bogusContainer {
	return []bogusContainer{
		{
			name:   "CnonApp",
			config: docker.Config{Image: "tsuru/python", Env: []string{"HOME=/"}},
			state:  docker.State{Running: true},
		},
		{
			name:   "Capp",
			config: docker.Config{Image: "tsuru/python", Env: []string{"HOME=/", "TSURU_APPNAME=someapp", "TSURU_PROCESSNAME=myprocess"}},
			state:  docker.State{Running: true},
		},
		{
			name:   "Ctest",
			config: docker.Config{Image: "tsuru/python", Env: []string{"HOME=/", "TSURU_APPNAME=someapp"}},
			state:  docker.State{Running: false, ExitCode: -1},
		},
	}
}

func (s *S) prepareStats(dockerServer *testing.DockerServer, containers []docker.Container) {
	for _, container := range containers {
		dockerServer.PrepareStats(container.ID, func(id string) docker.Stats {
			s := docker.Stats{}
			s.PreCPUStats.CPUUsage.TotalUsage = 50
			s.PreCPUStats.SystemCPUUsage = 20
			s.CPUStats.CPUUsage.TotalUsage = 100
			s.CPUStats.SystemCPUUsage = 40
			s.CPUStats.CPUUsage.PercpuUsage = []uint64{100}
			return s
		})
	}
}
<commit_msg>metric: fix flaky test<commit_after>// Copyright 2015 bs authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package metric

import (
	"net/http"
	"os"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/fsouza/go-dockerclient/testing"
	"gopkg.in/check.v1"
)

type bogusContainer struct {
	config docker.Config
	state  docker.State
	name   string
}

func (s *S) TestRunner(c *check.C) {
	os.Unsetenv("CONTAINER_SELECTION_ENV")
	bogusContainers := s.buildContainers()
	dockerServer, conts := s.startDockerServer(bogusContainers, nil, c)
	defer dockerServer.Stop()
	s.prepareStats(dockerServer, conts)
	r := NewRunner(dockerServer.URL(), time.Second, "fake")
	err := r.Start()
	c.Assert(err, check.IsNil)
	r.Stop()
	cpuStat := make([]*fakeStat, 0)
	for i, stat := range fakeStatter.stats {
		if stat.key == "cpu_max" {
			cpuStat = append(cpuStat, &fakeStatter.stats[i])
		}
	}
	c.Assert(len(cpuStat), check.Equals, 2)
	expected := []*fakeStat{
		{
			container: "nonApp",
			image:     "tsuru/python",
			hostname:  conts[0].ID[:12],
			key:       "cpu_max",
			value:     float(250),
		},
		{
			container: "app",
			app:       "someapp",
			image:     "tsuru/python",
			hostname:  conts[1].ID[:12],
			process:   "myprocess",
			key:       "cpu_max",
			value:     float(250),
		},
	}
	if cpuStat[0].hostname != conts[0].ID[:12] {
		expected[0], expected[1] = expected[1], expected[0]
	}
	for i, stat := range cpuStat {
		c.Assert(stat, check.DeepEquals, expected[i])
	}
}

func (s *S) TestRunnerSelectionEnv(c *check.C) {
	os.Setenv("CONTAINER_SELECTION_ENV", "TSURU_APPNAME")
	defer os.Unsetenv("CONTAINER_SELECTION_ENV")
	bogusContainers := s.buildContainers()
	dockerServer, conts := s.startDockerServer(bogusContainers, nil, c)
	defer dockerServer.Stop()
	s.prepareStats(dockerServer, conts)
	r := NewRunner(dockerServer.URL(), time.Second, "fake")
	err := r.Start()
	c.Assert(err, check.IsNil)
	r.Stop()
	cpuStat := make([]*fakeStat, 0)
	for i, stat := range fakeStatter.stats {
		if stat.key == "cpu_max" {
			cpuStat = append(cpuStat, &fakeStatter.stats[i])
		}
	}
	c.Assert(len(cpuStat), check.Equals, 1)
	expected := []*fakeStat{
		{
			container: "app",
			app:       "someapp",
			image:     "tsuru/python",
			hostname:  conts[1].ID[:12],
			process:   "myprocess",
			key:       "cpu_max",
			value:     float(250),
		},
	}
	c.Assert(cpuStat[0], check.DeepEquals, expected[0])
}

func (s *S) startDockerServer(containers []bogusContainer, hook func(*http.Request), c *check.C) (*testing.DockerServer, []docker.Container) {
	server, err := testing.NewServer("127.0.0.1:0", nil, hook)
	c.Assert(err, check.IsNil)
	client, err := docker.NewClient(server.URL())
	c.Assert(err, check.IsNil)
	createdContainers := make([]docker.Container, len(containers))
	for i, bogus := range containers {
		pullOpts := docker.PullImageOptions{Repository: bogus.config.Image}
		err = client.PullImage(pullOpts, docker.AuthConfiguration{})
		c.Assert(err, check.IsNil)
		createOpts := docker.CreateContainerOptions{Name: bogus.name, Config: &bogus.config}
		container, err := client.CreateContainer(createOpts)
		c.Assert(err, check.IsNil)
		err = server.MutateContainer(container.ID, bogus.state)
		c.Assert(err, check.IsNil)
		createdContainers[i] = *container
	}
	return server, createdContainers
}

func (s *S) buildContainers() []bogusContainer {
	return []bogusContainer{
		{
			name:   "CnonApp",
			config: docker.Config{Image: "tsuru/python", Env: []string{"HOME=/"}},
			state:  docker.State{Running: true},
		},
		{
			name:   "Capp",
			config: docker.Config{Image: "tsuru/python", Env: []string{"HOME=/", "TSURU_APPNAME=someapp", "TSURU_PROCESSNAME=myprocess"}},
			state:  docker.State{Running: true},
		},
		{
			name:   "Ctest",
			config: docker.Config{Image: "tsuru/python", Env: []string{"HOME=/", "TSURU_APPNAME=someapp"}},
			state:  docker.State{Running: false, ExitCode: -1},
		},
	}
}

func (s *S) prepareStats(dockerServer *testing.DockerServer, containers []docker.Container) {
	for _, container := range containers {
		dockerServer.PrepareStats(container.ID, func(id string) docker.Stats {
			s := docker.Stats{}
			s.PreCPUStats.CPUUsage.TotalUsage = 50
			s.PreCPUStats.SystemCPUUsage = 20
			s.CPUStats.CPUUsage.TotalUsage = 100
			s.CPUStats.SystemCPUUsage = 40
			s.CPUStats.CPUUsage.PercpuUsage = []uint64{100}
			return s
		})
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"html/template"
	"strings"
	"time"

	"github.com/admpub/humanize"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/tplfunc"
	"github.com/webx-top/echo/param"
)

func FuncMap(funcMap map[string]interface{}, skipper ...echo.Skipper) echo.MiddlewareFunc {
	var skip echo.Skipper
	if len(skipper) > 0 {
		skip = skipper[0]
	} else {
		skip = echo.DefaultSkipper
	}
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			if skip(c) {
				return h.Handle(c)
			}

			for name, function := range c.Echo().FuncMap {
				c.SetFunc(name, function)
			}
			for name, function := range funcMap {
				c.SetFunc(name, function)
			}
			SetDefaultFuncMap(c)
			return h.Handle(c)
		})
	}
}

func SimpleFuncMap(funcMap map[string]interface{}, skipper ...echo.Skipper) echo.MiddlewareFunc {
	var skip echo.Skipper
	if len(skipper) > 0 {
		skip = skipper[0]
	} else {
		skip = echo.DefaultSkipper
	}
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			if skip(c) {
				return h.Handle(c)
			}

			for name, function := range funcMap {
				c.SetFunc(name, function)
			}
			return h.Handle(c)
		})
	}
}

func SetDefaultFuncMap(c echo.Context) {
	req := c.Request()
	c.SetFunc(`T`, c.T)
	c.SetFunc(`Lang`, c.Lang)
	c.SetFunc(`Stored`, c.Stored)
	c.SetFunc(`Cookie`, c.Cookie)
	c.SetFunc(`Session`, c.Session)
	c.SetFunc(`Form`, c.Form)
	c.SetFunc(`Formx`, c.Formx)
	c.SetFunc(`Query`, c.Query)
	c.SetFunc(`Queryx`, c.Queryx)
	c.SetFunc(`FormValues`, c.FormValues)
	c.SetFunc(`QueryValues`, c.QueryValues)
	c.SetFunc(`FormxValues`, c.FormxValues)
	c.SetFunc(`GetByIndex`, param.GetByIndex)
	c.SetFunc(`QueryxValues`, c.QueryxValues)
	c.SetFunc(`Param`, c.Param)
	c.SetFunc(`Paramx`, c.Paramx)
	c.SetFunc(`Atop`, c.Atop)
	c.SetFunc(`URL`, req.URL)
	c.SetFunc(`URI`, req.URI)
	c.SetFunc(`Site`, c.Site)

	var pageURL string
	c.SetFunc(`SiteURI`, func() string {
		if len(pageURL) > 0 {
			return pageURL
		}
		pageURL = c.Site() + strings.TrimPrefix(req.URI(), `/`)
		return pageURL
	})
	c.SetFunc(`Referer`, c.Referer)
	c.SetFunc(`Header`, req.Header)
	c.SetFunc(`Flash`, c.Flash)
	c.SetFunc(`HasAnyRequest`, c.HasAnyRequest)
	c.SetFunc(`DurationFormat`, func(t interface{}, args ...string) *com.Durafmt {
		return tplfunc.DurationFormat(c.Lang().String(), t, args...)
	})
	c.SetFunc(`TsHumanize`, func(startTime interface{}, endTime ...interface{}) string {
		humanizer, err := humanize.New(c.Lang().String())
		if err != nil {
			return err.Error()
		}
		var (
			startDate = tplfunc.ToTime(startTime)
			endDate   time.Time
		)
		if len(endTime) > 0 {
			endDate = tplfunc.ToTime(endTime[0])
		}
		if endDate.IsZero() {
			endDate = time.Now().Local()
		}
		return humanizer.TimeDiff(endDate, startDate, 0)
	})
	c.SetFunc(`CaptchaForm`, func(args ...interface{}) template.HTML {
		return tplfunc.CaptchaFormWithURLPrefix(c.Echo().Prefix(), args...)
	})
	c.SetFunc(`MakeURL`, c.Echo().URL)
}
<commit_msg>update<commit_after>package middleware

import (
	"html/template"
	"strings"
	"time"

	"github.com/admpub/humanize"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/tplfunc"
	"github.com/webx-top/echo/param"
)

func FuncMap(funcMap map[string]interface{}, skipper ...echo.Skipper) echo.MiddlewareFunc {
	var skip echo.Skipper
	if len(skipper) > 0 {
		skip = skipper[0]
	} else {
		skip = echo.DefaultSkipper
	}
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			if skip(c) {
				return h.Handle(c)
			}

			for name, function := range c.Echo().FuncMap {
				c.SetFunc(name, function)
			}
			for name, function := range funcMap {
				c.SetFunc(name, function)
			}
			SetDefaultFuncMap(c)
			return h.Handle(c)
		})
	}
}

func SimpleFuncMap(funcMap map[string]interface{}, skipper ...echo.Skipper) echo.MiddlewareFunc {
	var skip echo.Skipper
	if len(skipper) > 0 {
		skip = skipper[0]
	} else {
		skip = echo.DefaultSkipper
	}
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			if skip(c) {
				return h.Handle(c)
			}

			for name, function := range funcMap {
				c.SetFunc(name, function)
			}
			return h.Handle(c)
		})
	}
}

func SetDefaultFuncMap(c echo.Context) {
	req := c.Request()
	c.SetFunc(`T`, c.T)
	c.SetFunc(`Lang`, c.Lang)
	var stored echo.Store
	c.SetFunc(`Stored`, func() echo.Store {
		if stored != nil {
			return stored
		}
		stored = c.Stored()
		return stored
	})
	c.SetFunc(`Get`, c.Get)
	c.SetFunc(`Set`, c.Set)
	c.SetFunc(`Cookie`, c.Cookie)
	c.SetFunc(`Session`, c.Session)
	c.SetFunc(`Form`, c.Form)
	c.SetFunc(`Formx`, c.Formx)
	c.SetFunc(`Query`, c.Query)
	c.SetFunc(`Queryx`, c.Queryx)
	c.SetFunc(`FormValues`, c.FormValues)
	c.SetFunc(`QueryValues`, c.QueryValues)
	c.SetFunc(`FormxValues`, c.FormxValues)
	c.SetFunc(`GetByIndex`, param.GetByIndex)
	c.SetFunc(`QueryxValues`, c.QueryxValues)
	c.SetFunc(`Param`, c.Param)
	c.SetFunc(`Paramx`, c.Paramx)
	c.SetFunc(`Atop`, c.Atop)
	c.SetFunc(`URL`, req.URL)
	c.SetFunc(`URI`, req.URI)
	c.SetFunc(`Site`, c.Site)

	var pageURL string
	c.SetFunc(`SiteURI`, func() string {
		if len(pageURL) > 0 {
			return pageURL
		}
		pageURL = c.Site() + strings.TrimPrefix(req.URI(), `/`)
		return pageURL
	})
	c.SetFunc(`Referer`, c.Referer)
	c.SetFunc(`Header`, req.Header)
	c.SetFunc(`Flash`, c.Flash)
	c.SetFunc(`HasAnyRequest`, c.HasAnyRequest)
	c.SetFunc(`DurationFormat`, func(t interface{}, args ...string) *com.Durafmt {
		return tplfunc.DurationFormat(c.Lang().String(), t, args...)
	})
	c.SetFunc(`TsHumanize`, func(startTime interface{}, endTime ...interface{}) string {
		humanizer, err := humanize.New(c.Lang().String())
		if err != nil {
			return err.Error()
		}
		var (
			startDate = tplfunc.ToTime(startTime)
			endDate   time.Time
		)
		if len(endTime) > 0 {
			endDate = tplfunc.ToTime(endTime[0])
		}
		if endDate.IsZero() {
			endDate = time.Now().Local()
		}
		return humanizer.TimeDiff(endDate, startDate, 0)
	})
	c.SetFunc(`CaptchaForm`, func(args ...interface{}) template.HTML {
		return tplfunc.CaptchaFormWithURLPrefix(c.Echo().Prefix(), args...)
	})
	c.SetFunc(`MakeURL`, c.Echo().URL)
}
<|endoftext|>


<commit_before>package spigot

func spigot(a, r, q int, carry <-chan int) <-chan int {
	c := make(chan int, 100)
	go func() {
		defer close(c)
		for cr := range carry {
			a = 10*a + cr
			c <- r * (a / q)
			a %= q
		}
	}()
	return c
}

func zero(n int) <-chan int {
	c := make(chan int)
	go func() {
		defer close(c)
		for i := 0; i < n; i++ {
			c <- 0
		}
	}()
	return c
}

// Pi2 calculates n digits of Pi concurently
func Pi2(n int) <-chan int {
	c := zero(n + 1)
	for i := 10*n/3 + 1; i > 0; i-- {
		c = spigot(2, i, 2*i+1, c)
	}
	return predigit(spigot(2, 1, 10, c))
}

// E2 calculates n digits of E concurently
func E2(n int) <-chan int {
	c := zero(n + 1)
	for i := n + 1; i > 0; i-- {
		c = spigot(1, 1, i+1, c)
	}
	return spigot(2, 1, 10, c)
}
<commit_msg>Hold up to 10 values<commit_after>package spigot

func spigot(a, r, q int, carry <-chan int) <-chan int {
	c := make(chan int, 10)
	go func() {
		defer close(c)
		for cr := range carry {
			a = 10*a + cr
			c <- r * (a / q)
			a %= q
		}
	}()
	return c
}

func zero(n int) <-chan int {
	c := make(chan int)
	go func() {
		defer close(c)
		for i := 0; i < n; i++ {
			c <- 0
		}
	}()
	return c
}

// Pi2 calculates n digits of Pi concurently
func Pi2(n int) <-chan int {
	c := zero(n + 1)
	for i := 10*n/3 + 1; i > 0; i-- {
		c = spigot(2, i, 2*i+1, c)
	}
	return predigit(spigot(2, 1, 10, c))
}

// E2 calculates n digits of E concurently
func E2(n int) <-chan int {
	c := zero(n + 1)
	for i := n + 1; i > 0; i-- {
		c = spigot(1, 1, i+1, c)
	}
	return spigot(2, 1, 10, c)
}
<|endoftext|>


<commit_before>// +build linux solaris

package libcontainerd

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	goruntime "runtime"
	"time"

	containerd "github.com/docker/containerd/api/grpc/types"
	"github.com/tonistiigi/fifo"
	"golang.org/x/net/context"
	"golang.org/x/sys/unix"
)

var fdNames = map[int]string{
	unix.Stdin:  "stdin",
	unix.Stdout: "stdout",
	unix.Stderr: "stderr",
}

// process keeps the state for both main container process and exec process.
type process struct {
	processCommon

	// Platform specific fields are below here.
	dir string
}

func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) {
	if err := os.MkdirAll(p.dir, 0700); err != nil {
		return nil, err
	}

	ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)

	io := &IOPipe{}

	io.Stdin, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdin), unix.O_WRONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			io.Stdin.Close()
		}
	}()

	io.Stdout, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdout), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			io.Stdout.Close()
		}
	}()

	if goruntime.GOOS == "solaris" || !terminal {
		// For Solaris terminal handling is done exclusively by the runtime therefore we make no distinction
		// in the processing for terminal and !terminal cases.
		io.Stderr, err = fifo.OpenFifo(ctx, p.fifo(unix.Stderr), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
		if err != nil {
			return nil, err
		}
		defer func() {
			if err != nil {
				io.Stderr.Close()
			}
		}()
	} else {
		io.Stderr = ioutil.NopCloser(emptyReader{})
	}

	return io, nil
}

func (p *process) sendCloseStdin() error {
	_, err := p.client.remote.apiClient.UpdateProcess(context.Background(), &containerd.UpdateProcessRequest{
		Id:         p.containerID,
		Pid:        p.friendlyName,
		CloseStdin: true,
	})
	return err
}

func (p *process) closeFifos(io *IOPipe) {
	io.Stdin.Close()
	io.Stdout.Close()
	io.Stderr.Close()
}

type emptyReader struct{}

func (r emptyReader) Read(b []byte) (int, error) {
	return 0, io.EOF
}

func (p *process) fifo(index int) string {
	return filepath.Join(p.dir, p.friendlyName+"-"+fdNames[index])
}
<commit_msg>Ignore "failed to close stdin" if container or process not found<commit_after>// +build linux solaris

package libcontainerd

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	goruntime "runtime"
	"strings"
	"time"

	containerd "github.com/docker/containerd/api/grpc/types"
	"github.com/tonistiigi/fifo"
	"golang.org/x/net/context"
	"golang.org/x/sys/unix"
)

var fdNames = map[int]string{
	unix.Stdin:  "stdin",
	unix.Stdout: "stdout",
	unix.Stderr: "stderr",
}

// process keeps the state for both main container process and exec process.
type process struct {
	processCommon

	// Platform specific fields are below here.
	dir string
}

func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) {
	if err := os.MkdirAll(p.dir, 0700); err != nil {
		return nil, err
	}

	ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)

	io := &IOPipe{}

	io.Stdin, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdin), unix.O_WRONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			io.Stdin.Close()
		}
	}()

	io.Stdout, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdout), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			io.Stdout.Close()
		}
	}()

	if goruntime.GOOS == "solaris" || !terminal {
		// For Solaris terminal handling is done exclusively by the runtime therefore we make no distinction
		// in the processing for terminal and !terminal cases.
		io.Stderr, err = fifo.OpenFifo(ctx, p.fifo(unix.Stderr), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
		if err != nil {
			return nil, err
		}
		defer func() {
			if err != nil {
				io.Stderr.Close()
			}
		}()
	} else {
		io.Stderr = ioutil.NopCloser(emptyReader{})
	}

	return io, nil
}

func (p *process) sendCloseStdin() error {
	_, err := p.client.remote.apiClient.UpdateProcess(context.Background(), &containerd.UpdateProcessRequest{
		Id:         p.containerID,
		Pid:        p.friendlyName,
		CloseStdin: true,
	})
	if err != nil && (strings.Contains(err.Error(), "container not found") || strings.Contains(err.Error(), "process not found")) {
		return nil
	}
	return err
}

func (p *process) closeFifos(io *IOPipe) {
	io.Stdin.Close()
	io.Stdout.Close()
	io.Stderr.Close()
}

type emptyReader struct{}

func (r emptyReader) Read(b []byte) (int, error) {
	return 0, io.EOF
}

func (p *process) fifo(index int) string {
	return filepath.Join(p.dir, p.friendlyName+"-"+fdNames[index])
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Julien Vehent jvehent@mozilla.com [:ulfr]
package main

import (
	"encoding/json"
	"fmt"
	"mig.ninja/mig"
	"mig.ninja/mig/modules"
	"mig.ninja/mig/modules/file"
	"time"
)

type ComplianceItem struct {
	Utctimestamp string           `json:"utctimestamp"`
	Target       string           `json:"target"`
	Policy       CompliancePolicy `json:"policy"`
	Check        ComplianceCheck  `json:"check"`
	Compliance   bool             `json:"compliance"`
	Link         string           `json:"link"`
	Tags         interface{}      `json:"tags"`
}

type CompliancePolicy struct {
	Name  string `json:"name"`
	URL   string `json:"url"`
	Level string `json:"level"`
}

type ComplianceCheck struct {
	Ref         string         `json:"ref"`
	Description string         `json:"description"`
	Name        string         `json:"name"`
	Location    string         `json:"location"`
	Test        ComplianceTest `json:"test"`
}

type ComplianceTest struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

type ComplianceTags struct {
	Operator string `json:"operator"`
}

func commandsToComplianceItems(commands []mig.Command) (items []ComplianceItem, err error) {
	for _, cmd := range commands {
		var bitem ComplianceItem
		bitem.Utctimestamp = cmd.FinishTime.UTC().Format(time.RFC3339Nano)
		bitem.Target = cmd.Agent.Name
		bitem.Policy.Name = cmd.Action.Threat.Type
		bitem.Policy.URL = cmd.Action.Description.URL
		bitem.Policy.Level = cmd.Action.Threat.Level
		bitem.Check.Ref = cmd.Action.Threat.Ref
		bitem.Check.Description = cmd.Action.Name
		bitem.Link = fmt.Sprintf("%s/command?commandid=%.0f", ctx.Server.BaseURL, cmd.ID)
		if _, ok := cmd.Agent.Tags.(map[string]interface{})["operator"]; ok {
			var t ComplianceTags
			t.Operator = cmd.Agent.Tags.(map[string]interface{})["operator"].(string)
			bitem.Tags = t
		}
		for i, result := range cmd.Results {
			buf, err := json.Marshal(result)
			if err != nil {
				return items, err
			}
			if i > (len(cmd.Action.Operations) - 1) {
				// skip this entry if the lookup fails
				continue
			}
			switch cmd.Action.Operations[i].Module {
			case "file":
				var el file.SearchResults
				var r modules.Result
				err = json.Unmarshal(buf, &r)
				if err != nil {
					return items, err
				}
				err = r.GetElements(&el)
				if err != nil {
					return items, err
				}
				for label, sr := range el {
					for _, mf := range sr {
						bitem.Check.Location = mf.File
						bitem.Check.Name = label
						bitem.Check.Test.Type = "file"
						bitem.Check.Test.Value = ""
						for _, v := range mf.Search.Names {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("name='%s'", v)
						}
						for _, v := range mf.Search.Sizes {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("size='%s'", v)
						}
						for _, v := range mf.Search.Modes {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("mode='%s'", v)
						}
						for _, v := range mf.Search.Mtimes {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("mtime='%s'", v)
						}
						for _, v := range mf.Search.Contents {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("content='%s'", v)
						}
						for _, v := range mf.Search.MD5 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("md5='%s'", v)
						}
						for _, v := range mf.Search.SHA1 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("sha1='%s'", v)
						}
						for _, v := range mf.Search.SHA2 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("sha2='%s'", v)
						}
						for _, v := range mf.Search.SHA3 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("sha3='%s'", v)
						}
						if mf.File == "" {
							for i, p := range mf.Search.Paths {
								if i > 0 {
									bitem.Check.Location += ", "
								}
								bitem.Check.Location += p
							}
							bitem.Compliance = false
						} else {
							bitem.Compliance = true
						}
						items = append(items, bitem)
					}
				}
			}
		}
	}
	return
}
<commit_msg>mig-api: commandsToComplianceItems, make Tags a map<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Julien Vehent jvehent@mozilla.com [:ulfr]
package main

import (
	"encoding/json"
	"fmt"
	"mig.ninja/mig"
	"mig.ninja/mig/modules"
	"mig.ninja/mig/modules/file"
	"time"
)

type ComplianceItem struct {
	Utctimestamp string            `json:"utctimestamp"`
	Target       string            `json:"target"`
	Policy       CompliancePolicy  `json:"policy"`
	Check        ComplianceCheck   `json:"check"`
	Compliance   bool              `json:"compliance"`
	Link         string            `json:"link"`
	Tags         map[string]string `json:"tags"`
}

type CompliancePolicy struct {
	Name  string `json:"name"`
	URL   string `json:"url"`
	Level string `json:"level"`
}

type ComplianceCheck struct {
	Ref         string         `json:"ref"`
	Description string         `json:"description"`
	Name        string         `json:"name"`
	Location    string         `json:"location"`
	Test        ComplianceTest `json:"test"`
}

type ComplianceTest struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

func commandsToComplianceItems(commands []mig.Command) (items []ComplianceItem, err error) {
	for _, cmd := range commands {
		var bitem ComplianceItem
		bitem.Utctimestamp = cmd.FinishTime.UTC().Format(time.RFC3339Nano)
		bitem.Target = cmd.Agent.Name
		bitem.Policy.Name = cmd.Action.Threat.Type
		bitem.Policy.URL = cmd.Action.Description.URL
		bitem.Policy.Level = cmd.Action.Threat.Level
		bitem.Check.Ref = cmd.Action.Threat.Ref
		bitem.Check.Description = cmd.Action.Name
		bitem.Link = fmt.Sprintf("%s/command?commandid=%.0f", ctx.Server.BaseURL, cmd.ID)
		if _, ok := cmd.Agent.Tags["operator"]; ok {
			bitem.Tags["operator"] = cmd.Agent.Tags["operator"]
		}
		for i, result := range cmd.Results {
			buf, err := json.Marshal(result)
			if err != nil {
				return items, err
			}
			if i > (len(cmd.Action.Operations) - 1) {
				// skip this entry if the lookup fails
				continue
			}
			switch cmd.Action.Operations[i].Module {
			case "file":
				var el file.SearchResults
				var r modules.Result
				err = json.Unmarshal(buf, &r)
				if err != nil {
					return items, err
				}
				err = r.GetElements(&el)
				if err != nil {
					return items, err
				}
				for label, sr := range el {
					for _, mf := range sr {
						bitem.Check.Location = mf.File
						bitem.Check.Name = label
						bitem.Check.Test.Type = "file"
						bitem.Check.Test.Value = ""
						for _, v := range mf.Search.Names {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("name='%s'", v)
						}
						for _, v := range mf.Search.Sizes {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("size='%s'", v)
						}
						for _, v := range mf.Search.Modes {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("mode='%s'", v)
						}
						for _, v := range mf.Search.Mtimes {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("mtime='%s'", v)
						}
						for _, v := range mf.Search.Contents {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("content='%s'", v)
						}
						for _, v := range mf.Search.MD5 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("md5='%s'", v)
						}
						for _, v := range mf.Search.SHA1 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("sha1='%s'", v)
						}
						for _, v := range mf.Search.SHA2 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("sha2='%s'", v)
						}
						for _, v := range mf.Search.SHA3 {
							if len(bitem.Check.Test.Value) > 0 {
								bitem.Check.Test.Value += " and "
							}
							bitem.Check.Test.Value += fmt.Sprintf("sha3='%s'", v)
						}
						if mf.File == "" {
							for i, p := range mf.Search.Paths {
								if i > 0 {
									bitem.Check.Location += ", "
								}
								bitem.Check.Location += p
							}
							bitem.Compliance = false
						} else {
							bitem.Compliance = true
						}
						items = append(items, bitem)
					}
				}
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package collector

// +build !nozfs

import (
	"errors"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
)

type zfsMetricValue int

const zfsErrorValue = zfsMetricValue(-1)

var zfsNotAvailableError = errors.New("ZFS / ZFS statistics are not available")

type zfsSysctl string
type zfsSubsystemName string

const (
	arc = zfsSubsystemName("zfs_arc")
)

// Metrics

type zfsMetric struct {
	subsystem zfsSubsystemName // The Prometheus subsystem name.
	name      string           // The Prometheus name of the metric.
	sysctl    zfsSysctl        // The sysctl of the ZFS metric.
}

func (m *zfsMetric) BuildFQName() string {
	return prometheus.BuildFQName(Namespace, string(m.subsystem), m.name)
}

// Collector

func init() {
	Factories["zfs"] = NewZFSCollector
}

type zfsCollector struct {
	zfsMetrics     []zfsMetric
	metricProvider zfsMetricProvider
}

func NewZFSCollector() (Collector, error) {
	return &zfsCollector{
		zfsMetrics: []zfsMetric{
			zfsMetric{arc, "mru_size", zfsSysctl("kstat.zfs.misc.arcstats.p")},
			zfsMetric{arc, "size", zfsSysctl("kstat.zfs.misc.arcstats.size")},
			zfsMetric{arc, "target_min_size", zfsSysctl("kstat.zfs.misc.arcstats.c_min")},
			zfsMetric{arc, "target_size", zfsSysctl("kstat.zfs.misc.arcstats.c")},
			zfsMetric{arc, "target_max_size", zfsSysctl("kstat.zfs.misc.arcstats.c_max")},
			zfsMetric{arc, "hits", zfsSysctl("kstat.zfs.misc.arcstats.hits")},
			zfsMetric{arc, "misses", zfsSysctl("kstat.zfs.misc.arcstats.misses")},
		},
		metricProvider: NewZFSMetricProvider(),
	}, nil
}

func (c *zfsCollector) Update(ch chan<- prometheus.Metric) (err error) {

	log.Debug("Preparing metrics update")
	err = c.metricProvider.PrepareUpdate()
	switch {
	case err == zfsNotAvailableError:
		log.Debug(err)
		return nil
	case err != nil:
		return err
	}
	defer c.metricProvider.InvalidateCache()

	log.Debugf("Fetching %d metrics", len(c.zfsMetrics))
	for _, metric := range c.zfsMetrics {

		value, err := c.metricProvider.Value(metric.sysctl)
		if err != nil {
			return err
		}

		ch <- prometheus.MustNewConstMetric(
			prometheus.NewDesc(
				metric.BuildFQName(),
				metric.HelpString(),
				nil,
				nil,
			),
			prometheus.UntypedValue,
			float64(value),
		)

	}

	return err
}

// Metrics Provider
// Platform-dependend parts implemented in zfs_${os} files.

type zfsMetricProvider struct {
	values map[zfsSysctl]zfsMetricValue
}

func NewZFSMetricProvider() zfsMetricProvider {
	return zfsMetricProvider{
		values: make(map[zfsSysctl]zfsMetricValue),
	}

}

func (p *zfsMetricProvider) InvalidateCache() {
	p.values = make(map[zfsSysctl]zfsMetricValue)
}

func (p *zfsMetricProvider) Value(s zfsSysctl) (value zfsMetricValue, err error) {

	var ok bool
	value = zfsErrorValue

	value, ok = p.values[s]
	if !ok {
		value, err = p.handleMiss(s)
		if err != nil {
			return value, err
		}
	}

	return value, err
}
<commit_msg>Remove race-condition in access on zfsMetricProvider in Update()<commit_after>package collector

// +build !nozfs

import (
	"errors"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
)

type zfsMetricValue int

const zfsErrorValue = zfsMetricValue(-1)

var zfsNotAvailableError = errors.New("ZFS / ZFS statistics are not available")

type zfsSysctl string
type zfsSubsystemName string

const (
	arc = zfsSubsystemName("zfs_arc")
)

// Metrics

type zfsMetric struct {
	subsystem zfsSubsystemName // The Prometheus subsystem name.
	name      string           // The Prometheus name of the metric.
	sysctl    zfsSysctl        // The sysctl of the ZFS metric.
}

func (m *zfsMetric) BuildFQName() string {
	return prometheus.BuildFQName(Namespace, string(m.subsystem), m.name)
}

func (m *zfsMetric) HelpString() string {
	return m.name
}

// Collector

func init() {
	Factories["zfs"] = NewZFSCollector
}

type zfsCollector struct {
	zfsMetrics     []zfsMetric
}

func NewZFSCollector() (Collector, error) {
	return &zfsCollector{
		zfsMetrics: []zfsMetric{
			zfsMetric{arc, "mru_size", zfsSysctl("kstat.zfs.misc.arcstats.p")},
			zfsMetric{arc, "size", zfsSysctl("kstat.zfs.misc.arcstats.size")},
			zfsMetric{arc, "target_min_size", zfsSysctl("kstat.zfs.misc.arcstats.c_min")},
			zfsMetric{arc, "target_size", zfsSysctl("kstat.zfs.misc.arcstats.c")},
			zfsMetric{arc, "target_max_size", zfsSysctl("kstat.zfs.misc.arcstats.c_max")},
			zfsMetric{arc, "hits", zfsSysctl("kstat.zfs.misc.arcstats.hits")},
			zfsMetric{arc, "misses", zfsSysctl("kstat.zfs.misc.arcstats.misses")},
		},
	}, nil
}

func (c *zfsCollector) Update(ch chan<- prometheus.Metric) (err error) {

	metricProvider := NewZFSMetricProvider()

	log.Debug("Preparing metrics update")
	err = metricProvider.PrepareUpdate()
	switch {
	case err == zfsNotAvailableError:
		log.Debug(err)
		return nil
	case err != nil:
		return err
	}

	log.Debugf("Fetching %d metrics", len(c.zfsMetrics))
	for _, metric := range c.zfsMetrics {

		value, err := metricProvider.Value(metric.sysctl)
		if err != nil {
			return err
		}

		ch <- prometheus.MustNewConstMetric(
			prometheus.NewDesc(
				metric.BuildFQName(),
				metric.HelpString(),
				nil,
				nil,
			),
			prometheus.UntypedValue,
			float64(value),
		)

	}

	return err
}

// Metrics Provider
// Platform-dependend parts implemented in zfs_${os} files.

type zfsMetricProvider struct {
	values map[zfsSysctl]zfsMetricValue
}

func NewZFSMetricProvider() zfsMetricProvider {
	return zfsMetricProvider{
		values: make(map[zfsSysctl]zfsMetricValue),
	}

}

func (p *zfsMetricProvider) Value(s zfsSysctl) (value zfsMetricValue, err error) {

	var ok bool
	value = zfsErrorValue

	value, ok = p.values[s]
	if !ok {
		value, err = p.handleMiss(s)
		if err != nil {
			return value, err
		}
	}

	return value, err
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package context

import (
	"strings"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/models/perm"
	user_model "code.gitea.io/gitea/models/user"
)

// Organization contains organization context
type Organization struct {
	IsOwner          bool
	IsMember         bool
	IsTeamMember     bool // Is member of team.
	IsTeamAdmin      bool // In owner team or team that has admin permission level.
	Organization     *models.Organization
	OrgLink          string
	CanCreateOrgRepo bool

	Team  *models.Team
	Teams []*models.Team
}

// HandleOrgAssignment handles organization assignment
func HandleOrgAssignment(ctx *Context, args ...bool) {
	var (
		requireMember     bool
		requireOwner      bool
		requireTeamMember bool
		requireTeamAdmin  bool
	)
	if len(args) >= 1 {
		requireMember = args[0]
	}
	if len(args) >= 2 {
		requireOwner = args[1]
	}
	if len(args) >= 3 {
		requireTeamMember = args[2]
	}
	if len(args) >= 4 {
		requireTeamAdmin = args[3]
	}

	orgName := ctx.Params(":org")

	var err error
	ctx.Org.Organization, err = models.GetOrgByName(orgName)
	if err != nil {
		if user_model.IsErrUserNotExist(err) {
			redirectUserID, err := user_model.LookupUserRedirect(orgName)
			if err == nil {
				RedirectToUser(ctx, orgName, redirectUserID)
			} else if user_model.IsErrUserRedirectNotExist(err) {
				ctx.NotFound("GetUserByName", err)
			} else {
				ctx.ServerError("LookupUserRedirect", err)
			}
		} else {
			ctx.ServerError("GetUserByName", err)
		}
		return
	}
	org := ctx.Org.Organization
	ctx.Data["Org"] = org

	teams, err := org.LoadTeams()
	if err != nil {
		ctx.ServerError("LoadTeams", err)
	}
	ctx.Data["OrgTeams"] = teams

	// Admin has super access.
	if ctx.IsSigned && ctx.User.IsAdmin {
		ctx.Org.IsOwner = true
		ctx.Org.IsMember = true
		ctx.Org.IsTeamMember = true
		ctx.Org.IsTeamAdmin = true
		ctx.Org.CanCreateOrgRepo = true
	} else if ctx.IsSigned {
		ctx.Org.IsOwner, err = org.IsOwnedBy(ctx.User.ID)
		if err != nil {
			ctx.ServerError("IsOwnedBy", err)
			return
		}

		if ctx.Org.IsOwner {
			ctx.Org.IsMember = true
			ctx.Org.IsTeamMember = true
			ctx.Org.IsTeamAdmin = true
			ctx.Org.CanCreateOrgRepo = true
		} else {
			ctx.Org.IsMember, err = org.IsOrgMember(ctx.User.ID)
			if err != nil {
				ctx.ServerError("IsOrgMember", err)
				return
			}
			ctx.Org.CanCreateOrgRepo, err = org.CanCreateOrgRepo(ctx.User.ID)
			if err != nil {
				ctx.ServerError("CanCreateOrgRepo", err)
				return
			}
		}
	} else {
		// Fake data.
		ctx.Data["SignedUser"] = &user_model.User{}
	}
	if (requireMember && !ctx.Org.IsMember) ||
		(requireOwner && !ctx.Org.IsOwner) {
		ctx.NotFound("OrgAssignment", err)
		return
	}
	ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
	ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
	ctx.Data["IsPublicMember"] = func(uid int64) bool {
		is, _ := models.IsPublicMembership(ctx.Org.Organization.ID, uid)
		return is
	}
	ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo

	ctx.Org.OrgLink = org.AsUser().OrganisationLink()
	ctx.Data["OrgLink"] = ctx.Org.OrgLink

	// Team.
	if ctx.Org.IsMember {
		if ctx.Org.IsOwner {
			ctx.Org.Teams, err = org.LoadTeams()
			if err != nil {
				ctx.ServerError("LoadTeams", err)
				return
			}
		} else {
			ctx.Org.Teams, err = org.GetUserTeams(ctx.User.ID)
			if err != nil {
				ctx.ServerError("GetUserTeams", err)
				return
			}
		}
	}

	teamName := ctx.Params(":team")
	if len(teamName) > 0 {
		teamExists := false
		for _, team := range ctx.Org.Teams {
			if team.LowerName == strings.ToLower(teamName) {
				teamExists = true
				ctx.Org.Team = team
				ctx.Org.IsTeamMember = true
				ctx.Data["Team"] = ctx.Org.Team
				break
			}
		}

		if !teamExists {
			ctx.NotFound("OrgAssignment", err)
			return
		}

		ctx.Data["IsTeamMember"] = ctx.Org.IsTeamMember
		if requireTeamMember && !ctx.Org.IsTeamMember {
			ctx.NotFound("OrgAssignment", err)
			return
		}

		ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.AccessMode >= perm.AccessModeAdmin
		ctx.Data["IsTeamAdmin"] = ctx.Org.IsTeamAdmin
		if requireTeamAdmin && !ctx.Org.IsTeamAdmin {
			ctx.NotFound("OrgAssignment", err)
			return
		}
	}
}

// OrgAssignment returns a middleware to handle organization assignment
func OrgAssignment(args ...bool) func(ctx *Context) {
	return func(ctx *Context) {
		HandleOrgAssignment(ctx, args...)
	}
}
<commit_msg>Allow adminstrator teams members to see other teams (#18918)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package context

import (
	"strings"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/models/perm"
	user_model "code.gitea.io/gitea/models/user"
)

// Organization contains organization context
type Organization struct {
	IsOwner          bool
	IsMember         bool
	IsTeamMember     bool // Is member of team.
	IsTeamAdmin      bool // In owner team or team that has admin permission level.
	Organization     *models.Organization
	OrgLink          string
	CanCreateOrgRepo bool

	Team  *models.Team
	Teams []*models.Team
}

// HandleOrgAssignment handles organization assignment
func HandleOrgAssignment(ctx *Context, args ...bool) {
	var (
		requireMember     bool
		requireOwner      bool
		requireTeamMember bool
		requireTeamAdmin  bool
	)
	if len(args) >= 1 {
		requireMember = args[0]
	}
	if len(args) >= 2 {
		requireOwner = args[1]
	}
	if len(args) >= 3 {
		requireTeamMember = args[2]
	}
	if len(args) >= 4 {
		requireTeamAdmin = args[3]
	}

	orgName := ctx.Params(":org")

	var err error
	ctx.Org.Organization, err = models.GetOrgByName(orgName)
	if err != nil {
		if user_model.IsErrUserNotExist(err) {
			redirectUserID, err := user_model.LookupUserRedirect(orgName)
			if err == nil {
				RedirectToUser(ctx, orgName, redirectUserID)
			} else if user_model.IsErrUserRedirectNotExist(err) {
				ctx.NotFound("GetUserByName", err)
			} else {
				ctx.ServerError("LookupUserRedirect", err)
			}
		} else {
			ctx.ServerError("GetUserByName", err)
		}
		return
	}
	org := ctx.Org.Organization
	ctx.Data["Org"] = org

	teams, err := org.LoadTeams()
	if err != nil {
		ctx.ServerError("LoadTeams", err)
	}
	ctx.Data["OrgTeams"] = teams

	// Admin has super access.
	if ctx.IsSigned && ctx.User.IsAdmin {
		ctx.Org.IsOwner = true
		ctx.Org.IsMember = true
		ctx.Org.IsTeamMember = true
		ctx.Org.IsTeamAdmin = true
		ctx.Org.CanCreateOrgRepo = true
	} else if ctx.IsSigned {
		ctx.Org.IsOwner, err = org.IsOwnedBy(ctx.User.ID)
		if err != nil {
			ctx.ServerError("IsOwnedBy", err)
			return
		}

		if ctx.Org.IsOwner {
			ctx.Org.IsMember = true
			ctx.Org.IsTeamMember = true
			ctx.Org.IsTeamAdmin = true
			ctx.Org.CanCreateOrgRepo = true
		} else {
			ctx.Org.IsMember, err = org.IsOrgMember(ctx.User.ID)
			if err != nil {
				ctx.ServerError("IsOrgMember", err)
				return
			}
			ctx.Org.CanCreateOrgRepo, err = org.CanCreateOrgRepo(ctx.User.ID)
			if err != nil {
				ctx.ServerError("CanCreateOrgRepo", err)
				return
			}
		}
	} else {
		// Fake data.
		ctx.Data["SignedUser"] = &user_model.User{}
	}
	if (requireMember && !ctx.Org.IsMember) ||
		(requireOwner && !ctx.Org.IsOwner) {
		ctx.NotFound("OrgAssignment", err)
		return
	}
	ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
	ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
	ctx.Data["IsPublicMember"] = func(uid int64) bool {
		is, _ := models.IsPublicMembership(ctx.Org.Organization.ID, uid)
		return is
	}
	ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo

	ctx.Org.OrgLink = org.AsUser().OrganisationLink()
	ctx.Data["OrgLink"] = ctx.Org.OrgLink

	// Team.
	if ctx.Org.IsMember {
		shouldSeeAllTeams := false
		if ctx.Org.IsOwner {
			shouldSeeAllTeams = true
		} else {
			teams, err := org.GetUserTeams(ctx.User.ID)
			if err != nil {
				ctx.ServerError("GetUserTeams", err)
				return
			}
			for _, team := range teams {
				if team.IncludesAllRepositories && team.AccessMode >= perm.AccessModeAdmin {
					shouldSeeAllTeams = true
					break
				}
			}
		}
		if shouldSeeAllTeams {
			ctx.Org.Teams, err = org.LoadTeams()
			if err != nil {
				ctx.ServerError("LoadTeams", err)
				return
			}
		} else {
			ctx.Org.Teams, err = org.GetUserTeams(ctx.User.ID)
			if err != nil {
				ctx.ServerError("GetUserTeams", err)
				return
			}
		}
	}

	teamName := ctx.Params(":team")
	if len(teamName) > 0 {
		teamExists := false
		for _, team := range ctx.Org.Teams {
			if team.LowerName == strings.ToLower(teamName) {
				teamExists = true
				ctx.Org.Team = team
				ctx.Org.IsTeamMember = true
				ctx.Data["Team"] = ctx.Org.Team
				break
			}
		}

		if !teamExists {
			ctx.NotFound("OrgAssignment", err)
			return
		}

		ctx.Data["IsTeamMember"] = ctx.Org.IsTeamMember
		if requireTeamMember && !ctx.Org.IsTeamMember {
			ctx.NotFound("OrgAssignment", err)
			return
		}

		ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.AccessMode >= perm.AccessModeAdmin
		ctx.Data["IsTeamAdmin"] = ctx.Org.IsTeamAdmin
		if requireTeamAdmin && !ctx.Org.IsTeamAdmin {
			ctx.NotFound("OrgAssignment", err)
			return
		}
	}
}

// OrgAssignment returns a middleware to handle organization assignment
func OrgAssignment(args ...bool) func(ctx *Context) {
	return func(ctx *Context) {
		HandleOrgAssignment(ctx, args...)
	}
}
<|endoftext|>


<commit_before>package sqldb

import (
	"bytes"
	"database/sql"
	"fmt"
	"strings"
)

type ColumnNames []string

type ColumnNameJoinRule interface {
	Separator() string
	Append(buffer *bytes.Buffer, c string)
}

type columnNameJoinAsList struct{}

var _ ColumnNameJoinRule = columnNameJoinAsList{}

func (columnNameJoinAsList) Separator() string { return ", " }

func (columnNameJoinAsList) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
}

type columnNameJoinAsNamedList struct{}

var _ ColumnNameJoinRule = columnNameJoinAsNamedList{}

func (columnNameJoinAsNamedList) Separator() string { return ", " }

func (columnNameJoinAsNamedList) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(":")
	buffer.WriteString(c)
}

type columnNameJoinAsUpdate struct{}

var _ ColumnNameJoinRule = columnNameJoinAsUpdate{}

func (columnNameJoinAsUpdate) Separator() string { return ", " }

func (columnNameJoinAsUpdate) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" = ?")
}

type columnNameJoinAsNamedUpdate struct{}

var _ ColumnNameJoinRule = columnNameJoinAsNamedUpdate{}

func (columnNameJoinAsNamedUpdate) Separator() string { return ", " }

func (columnNameJoinAsNamedUpdate) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" = :")
	buffer.WriteString(c)
}

type columnNameJoinAsCond struct{ Cond string }

var _ ColumnNameJoinRule = columnNameJoinAsCond{}

func (c columnNameJoinAsCond) Separator() string { return " " + c.Cond + " " }

func (columnNameJoinAsCond) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" = ?")
}

type columnNameJoinAsNamedCond struct{ Cond string }

var _ ColumnNameJoinRule = columnNameJoinAsNamedCond{}

func (c columnNameJoinAsNamedCond) Separator() string { return " " + c.Cond + " " }

func (columnNameJoinAsNamedCond) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" = :")
	buffer.WriteString(c)
}

func (c ColumnNames) Join(rule ColumnNameJoinRule) string {
	var b bytes.Buffer
	for _, c := range c {
		if b.Len() > 0 {
			b.WriteString(rule.Separator())
		}
		rule.Append(&b, c)
	}
	return b.String()
}

func (c ColumnNames) List() string {
	return c.Join(columnNameJoinAsList{})
}

func (c ColumnNames) NamedList() string {
	return c.Join(columnNameJoinAsNamedList{})
}

func (c ColumnNames) Update() string {
	return c.Join(columnNameJoinAsUpdate{})
}

func (c ColumnNames) NamedUpdate() string {
	return c.Join(columnNameJoinAsNamedUpdate{})
}

func (c ColumnNames) Cond(cond string) string {
	return c.Join(columnNameJoinAsCond{})
}

func (c ColumnNames) NamedCond(cond string) string {
	return c.Join(columnNameJoinAsNamedCond{})
}

func (c ColumnNames) Contains(col string) bool {
	for _, s := range c {
		if s == col {
			return true
		}
	}
	return false
}

func (c ColumnNames) Copy() ColumnNames {
	nc := make(ColumnNames, len(c))
	copy(nc, c)
	return nc
}

func (c ColumnNames) InplaceRemove(cols ...string) ColumnNames {
	var end int
	for i, col := range c {
		if !ColumnNames(cols).Contains(col) {
			if i != end {
				c[end] = col
			}
			end++
		}
	}
	c = c[:end]
	return c
}

type SQLUtil struct {
	dialect DBDialect
	parser  *TableParser
}

func NewSQLUtil(parser *TableParser, dialect DBDialect) *SQLUtil {
	return &SQLUtil{
		parser:  parser,
		dialect: dialect,
	}
}
func (s *SQLUtil) TableParser() *TableParser {
	return s.parser
}
func (s *SQLUtil) DBDialect() DBDialect {
	return s.dialect
}

func (s *SQLUtil) TableColumns(v interface{}, excepts ...string) ColumnNames {
	t, err := s.parser.StructTable(v)
	if err != nil {
		return nil
	}
	cols := make(ColumnNames, 0, len(t.Cols))
	for _, c := range t.Cols {
		if !ColumnNames(excepts).Contains(c.Name) {
			cols = append(cols, c.Name)
		}
	}
	return cols
}

func (s *SQLUtil) CreateTables(db *sql.DB, models ...interface{}) error {
	for _, mod := range models {
		table, err := s.parser.StructTable(mod)
		if err != nil {
			return err
		}
		s, err := s.CreateTableSQL(table)
		if err != nil {
			return fmt.Errorf("%s: %s", table.Name, err.Error())
		}
		_, err = db.Exec(s)
		if err != nil {
			return fmt.Errorf("%s: %s", table.Name, err.Error())
		}
	}
	return nil
}

func (s *SQLUtil) escapeName(name string) string {
	return `"` + name + `"`
}

func (s *SQLUtil) CreateTableSQL(table Table) (string, error) {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "CREATE TABLE IF NOT EXISTS %s (\n", s.escapeName(table.Name))
	var (
		uniques   map[string][]string
		primaries []string
		foreigns  []int
		lastQuite string
	)
	for i, col := range table.Cols {
		dbTyp, defaultVal, err := s.dialect.Type(col.Type, col.Precision, col.DefaultVal)
		if err != nil {
			return "", err
		}
		if col.Primary {
			primaries = append(primaries, s.escapeName(col.Name))
		}
		if col.ForeignTable != "" {
			foreigns = append(foreigns, i)
		}
		if col.DBType != "" {
			dbTyp = col.DBType
		}
		var constraints string
		if col.Unique {
			if col.UniqueName == "" {
				constraints += " UNIQUE"
			} else {
				if uniques == nil {
					uniques = make(map[string][]string)
				}
				uniques[col.UniqueName] = append(uniques[col.UniqueName], s.escapeName(col.Name))
			}
		}
		if col.AutoIncr {
			constraints += " AUTO INCREAMENT"
		}
		if !col.Notnull {
			constraints += " NOT NULL"
		}
		if col.Default {
			constraints += " DEFAULT " + defaultVal
		}
		lastQuite = ""
		if i != len(table.Cols)-1 || len(primaries) != 0 || len(uniques) != 0 || len(foreigns) != 0 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    %s %s %s%s\n", s.escapeName(col.Name), dbTyp, constraints, lastQuite)
	}
	if len(primaries) > 0 {
		lastQuite = ""
		if len(uniques) != 0 || len(foreigns) != 0 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    PRIMARY KEY (%s)%s\n", strings.Join(primaries, ","), lastQuite)
	}
	for name, keys := range uniques {
		lastQuite = ""
		if len(foreigns) != 0 || len(uniques) != 1 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    CONSTRAINT %s UNIQUE (%s)%s\n", name, strings.Join(keys, ","), lastQuite)
		delete(uniques, name)
	}
	for i, index := range foreigns {
		col := table.Cols[index]
		lastQuite = ""
		if i != len(foreigns)-1 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    FOREIGN KEY(%s) REFERENCES %s(%s)%s\n", s.escapeName(col.Name), col.ForeignTable, col.ForeignCol, lastQuite)
	}
	fmt.Fprintf(&buf, ");\n")
	return buf.String(), nil
}
<commit_msg>fixed columns join with cond<commit_after>package sqldb

import (
	"bytes"
	"database/sql"
	"fmt"
	"strings"
)

type ColumnNames []string

type ColumnNameJoinRule interface {
	Separator() string
	Append(buffer *bytes.Buffer, c string)
}

type columnNameJoinAsList struct{}

var _ ColumnNameJoinRule = columnNameJoinAsList{}

func (columnNameJoinAsList) Separator() string { return ", " }

func (columnNameJoinAsList) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
}

type columnNameJoinAsNamedList struct{}

var _ ColumnNameJoinRule = columnNameJoinAsNamedList{}

func (columnNameJoinAsNamedList) Separator() string { return ", " }

func (columnNameJoinAsNamedList) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(":")
	buffer.WriteString(c)
}

type columnNameJoinAsUpdate struct{}

var _ ColumnNameJoinRule = columnNameJoinAsUpdate{}

func (columnNameJoinAsUpdate) Separator() string { return ", " }

func (columnNameJoinAsUpdate) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" = ?")
}

type columnNameJoinAsNamedUpdate struct{}

var _ ColumnNameJoinRule = columnNameJoinAsNamedUpdate{}

func (columnNameJoinAsNamedUpdate) Separator() string { return ", " }

func (columnNameJoinAsNamedUpdate) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" = :")
	buffer.WriteString(c)
}

type columnNameJoinAsCond struct {
	Cond  string
	Check string
}

var _ ColumnNameJoinRule = columnNameJoinAsCond{}

func (cd columnNameJoinAsCond) Separator() string { return " " + cd.Cond + " " }

func (cd columnNameJoinAsCond) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" " + cd.Check + " ?")
}

type columnNameJoinAsNamedCond struct {
	Cond  string
	Check string
}

var _ ColumnNameJoinRule = columnNameJoinAsNamedCond{}

func (cd columnNameJoinAsNamedCond) Separator() string { return " " + cd.Cond + " " }

func (cd columnNameJoinAsNamedCond) Append(buffer *bytes.Buffer, c string) {
	buffer.WriteString(c)
	buffer.WriteString(" " + cd.Check + " :")
	buffer.WriteString(c)
}

func (c ColumnNames) Join(rule ColumnNameJoinRule) string {
	var b bytes.Buffer
	for _, c := range c {
		if b.Len() > 0 {
			b.WriteString(rule.Separator())
		}
		rule.Append(&b, c)
	}
	return b.String()
}

func (c ColumnNames) List() string {
	return c.Join(columnNameJoinAsList{})
}

func (c ColumnNames) NamedList() string {
	return c.Join(columnNameJoinAsNamedList{})
}

func (c ColumnNames) Update() string {
	return c.Join(columnNameJoinAsUpdate{})
}

func (c ColumnNames) NamedUpdate() string {
	return c.Join(columnNameJoinAsNamedUpdate{})
}

func (c ColumnNames) Cond(cond, check string) string {
	return c.Join(columnNameJoinAsCond{Cond: cond, Check: check})
}

func (c ColumnNames) NamedCond(cond, check string) string {
	return c.Join(columnNameJoinAsNamedCond{Cond: cond, Check: check})
}

func (c ColumnNames) Contains(col string) bool {
	for _, s := range c {
		if s == col {
			return true
		}
	}
	return false
}

func (c ColumnNames) Copy() ColumnNames {
	nc := make(ColumnNames, len(c))
	copy(nc, c)
	return nc
}

func (c ColumnNames) InplaceRemove(cols ...string) ColumnNames {
	var end int
	for i, col := range c {
		if !ColumnNames(cols).Contains(col) {
			if i != end {
				c[end] = col
			}
			end++
		}
	}
	c = c[:end]
	return c
}

type SQLUtil struct {
	dialect DBDialect
	parser  *TableParser
}

func NewSQLUtil(parser *TableParser, dialect DBDialect) *SQLUtil {
	return &SQLUtil{
		parser:  parser,
		dialect: dialect,
	}
}
func (s *SQLUtil) TableParser() *TableParser {
	return s.parser
}
func (s *SQLUtil) DBDialect() DBDialect {
	return s.dialect
}

func (s *SQLUtil) TableColumns(v interface{}, excepts ...string) ColumnNames {
	t, err := s.parser.StructTable(v)
	if err != nil {
		return nil
	}
	cols := make(ColumnNames, 0, len(t.Cols))
	for _, c := range t.Cols {
		if !ColumnNames(excepts).Contains(c.Name) {
			cols = append(cols, c.Name)
		}
	}
	return cols
}

func (s *SQLUtil) CreateTables(db *sql.DB, models ...interface{}) error {
	for _, mod := range models {
		table, err := s.parser.StructTable(mod)
		if err != nil {
			return err
		}
		s, err := s.CreateTableSQL(table)
		if err != nil {
			return fmt.Errorf("%s: %s", table.Name, err.Error())
		}
		_, err = db.Exec(s)
		if err != nil {
			return fmt.Errorf("%s: %s", table.Name, err.Error())
		}
	}
	return nil
}

func (s *SQLUtil) escapeName(name string) string {
	return `"` + name + `"`
}

func (s *SQLUtil) CreateTableSQL(table Table) (string, error) {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "CREATE TABLE IF NOT EXISTS %s (\n", s.escapeName(table.Name))
	var (
		uniques   map[string][]string
		primaries []string
		foreigns  []int
		lastQuite string
	)
	for i, col := range table.Cols {
		dbTyp, defaultVal, err := s.dialect.Type(col.Type, col.Precision, col.DefaultVal)
		if err != nil {
			return "", err
		}
		if col.Primary {
			primaries = append(primaries, s.escapeName(col.Name))
		}
		if col.ForeignTable != "" {
			foreigns = append(foreigns, i)
		}
		if col.DBType != "" {
			dbTyp = col.DBType
		}
		var constraints string
		if col.Unique {
			if col.UniqueName == "" {
				constraints += " UNIQUE"
			} else {
				if uniques == nil {
					uniques = make(map[string][]string)
				}
				uniques[col.UniqueName] = append(uniques[col.UniqueName], s.escapeName(col.Name))
			}
		}
		if col.AutoIncr {
			constraints += " AUTO INCREAMENT"
		}
		if !col.Notnull {
			constraints += " NOT NULL"
		}
		if col.Default {
			constraints += " DEFAULT " + defaultVal
		}
		lastQuite = ""
		if i != len(table.Cols)-1 || len(primaries) != 0 || len(uniques) != 0 || len(foreigns) != 0 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    %s %s %s%s\n", s.escapeName(col.Name), dbTyp, constraints, lastQuite)
	}
	if len(primaries) > 0 {
		lastQuite = ""
		if len(uniques) != 0 || len(foreigns) != 0 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    PRIMARY KEY (%s)%s\n", strings.Join(primaries, ","), lastQuite)
	}
	for name, keys := range uniques {
		lastQuite = ""
		if len(foreigns) != 0 || len(uniques) != 1 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    CONSTRAINT %s UNIQUE (%s)%s\n", name, strings.Join(keys, ","), lastQuite)
		delete(uniques, name)
	}
	for i, index := range foreigns {
		col := table.Cols[index]
		lastQuite = ""
		if i != len(foreigns)-1 {
			lastQuite = ","
		}
		fmt.Fprintf(&buf, "    FOREIGN KEY(%s) REFERENCES %s(%s)%s\n", s.escapeName(col.Name), col.ForeignTable, col.ForeignCol, lastQuite)
	}
	fmt.Fprintf(&buf, ");\n")
	return buf.String(), nil
}
<|endoftext|>


<commit_before>// +build darwin

package mem

import (
	"testing"
)

var vm_stat_out = `
Mach Virtual Memory Statistics: (page size of 4096 bytes)
Pages free:                              105885.
Pages active:                            725641.
Pages inactive:                          449242.
Pages speculative:                         6155.
Pages throttled:                              0.
Pages wired down:                        560835.
Pages purgeable:                         128967.
"Translation faults":                 622528839.
Pages copy-on-write:                   17697839.
Pages zero filled:                    311034413.
Pages reactivated:                      4705104.
Pages purged:                           5605610.
File-backed pages:                       349192.
Anonymous pages:                         831846.
Pages stored in compressor:              876507.
Pages occupied by compressor:            249167.
Decompressions:                         4555025.
Compressions:                           7524729.
Pageins:                               40532443.
Pageouts:                                126496.
Swapins:                                2988073.
Swapouts:                               3283599.
`

func TestParseVmStat(t *testing.T) {
	ret := &VirtualMemoryStat{}
	err := parseVmStat(vm_stat_out, 4096, ret)

	if err != nil {
		t.Errorf("Expected no error, got %s\n", err.Error())
	}

	if ret.Free != uint64(105885*4096) {
		t.Errorf("Free pages, actual: %d, expected: %d", ret.Free,
			105885*4096)
	}

	if ret.Inactive != uint64(449242*4096) {
		t.Errorf("Inactive pages, actual: %d, expected: %d", ret.Inactive,
			449242*4096)
	}

	if ret.Active != uint64(725641*4096) {
		t.Errorf("Active pages, actual: %d, expected: %d", ret.Active,
			725641*4096)
	}

	if ret.Wired != uint64(560835*4096) {
		t.Errorf("Wired pages, actual: %d, expected: %d", ret.Wired,
			560835*4096)
	}

	if ret.Cached != uint64(128967*4096+449242.*4096) {
		t.Errorf("Cached pages, actual: %d, expected: %f", ret.Cached,
			128967*4096+449242.*4096)
	}
}
<commit_msg>Add Darwin specific mem.VirtualMemory() tests<commit_after>// +build darwin

package mem

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var vmStatOut = `
Mach Virtual Memory Statistics: (page size of 4096 bytes)
Pages free:                              105885.
Pages active:                            725641.
Pages inactive:                          449242.
Pages speculative:                         6155.
Pages throttled:                              0.
Pages wired down:                        560835.
Pages purgeable:                         128967.
"Translation faults":                 622528839.
Pages copy-on-write:                   17697839.
Pages zero filled:                    311034413.
Pages reactivated:                      4705104.
Pages purged:                           5605610.
File-backed pages:                       349192.
Anonymous pages:                         831846.
Pages stored in compressor:              876507.
Pages occupied by compressor:            249167.
Decompressions:                         4555025.
Compressions:                           7524729.
Pageins:                               40532443.
Pageouts:                                126496.
Swapins:                                2988073.
Swapouts:                               3283599.
`

func TestParseVmStat(t *testing.T) {
	ret := &VirtualMemoryStat{}
	err := parseVmStat(vmStatOut, 4096, ret)

	if err != nil {
		t.Errorf("Expected no error, got %s\n", err.Error())
	}

	if ret.Free != uint64(105885*4096) {
		t.Errorf("Free pages, actual: %d, expected: %d", ret.Free,
			105885*4096)
	}

	if ret.Inactive != uint64(449242*4096) {
		t.Errorf("Inactive pages, actual: %d, expected: %d", ret.Inactive,
			449242*4096)
	}

	if ret.Active != uint64(725641*4096) {
		t.Errorf("Active pages, actual: %d, expected: %d", ret.Active,
			725641*4096)
	}

	if ret.Wired != uint64(560835*4096) {
		t.Errorf("Wired pages, actual: %d, expected: %d", ret.Wired,
			560835*4096)
	}

	if ret.Cached != uint64(128967*4096+449242.*4096) {
		t.Errorf("Cached pages, actual: %d, expected: %f", ret.Cached,
			128967*4096+449242.*4096)
	}
}

func TestVirtualMemoryDarwin(t *testing.T) {
	v, err := VirtualMemory()
	assert.Nil(t, err)

	assert.True(t, v.Total > 0)

	assert.True(t, v.Available > 0)
	assert.True(t, v.Available < v.Total)
	assert.Equal(t, v.Available, v.Total-v.Wired-v.Active, "%v", v)

	assert.True(t, v.Used > 0)
	assert.True(t, v.Used < v.Total)

	assert.True(t, v.UsedPercent > 0)
	assert.True(t, v.UsedPercent < 100)

	assert.True(t, v.Free > 0)
	assert.True(t, v.Free < v.Available)

	assert.True(t, v.Active > 0)
	assert.True(t, v.Active < v.Total)

	assert.True(t, v.Inactive > 0)
	assert.True(t, v.Inactive < v.Total)

	assert.True(t, v.Wired > 0)
	assert.True(t, v.Wired < v.Total)
}
<|endoftext|>