2016-09-08 13:11:39 -04:00
package formatter
import (
"bytes"
2016-09-13 03:01:31 -04:00
"encoding/json"
2016-09-08 13:11:39 -04:00
"fmt"
"strings"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
2016-09-08 15:11:38 -04:00
"github.com/docker/docker/pkg/testutil/assert"
2016-09-08 13:11:39 -04:00
)
func TestContainerPsContext ( t * testing . T ) {
containerID := stringid . GenerateRandomID ( )
unix := time . Now ( ) . Add ( - 65 * time . Second ) . Unix ( )
var ctx containerContext
cases := [ ] struct {
container types . Container
trunc bool
expValue string
expHeader string
call func ( ) string
} {
{ types . Container { ID : containerID } , true , stringid . TruncateID ( containerID ) , containerIDHeader , ctx . ID } ,
{ types . Container { ID : containerID } , false , containerID , containerIDHeader , ctx . ID } ,
{ types . Container { Names : [ ] string { "/foobar_baz" } } , true , "foobar_baz" , namesHeader , ctx . Names } ,
{ types . Container { Image : "ubuntu" } , true , "ubuntu" , imageHeader , ctx . Image } ,
{ types . Container { Image : "verylongimagename" } , true , "verylongimagename" , imageHeader , ctx . Image } ,
{ types . Container { Image : "verylongimagename" } , false , "verylongimagename" , imageHeader , ctx . Image } ,
{ types . Container {
Image : "a5a665ff33eced1e0803148700880edab4" ,
ImageID : "a5a665ff33eced1e0803148700880edab4269067ed77e27737a708d0d293fbf5" ,
} ,
true ,
"a5a665ff33ec" ,
imageHeader ,
ctx . Image ,
} ,
{ types . Container {
Image : "a5a665ff33eced1e0803148700880edab4" ,
ImageID : "a5a665ff33eced1e0803148700880edab4269067ed77e27737a708d0d293fbf5" ,
} ,
false ,
"a5a665ff33eced1e0803148700880edab4" ,
imageHeader ,
ctx . Image ,
} ,
{ types . Container { Image : "" } , true , "<no image>" , imageHeader , ctx . Image } ,
{ types . Container { Command : "sh -c 'ls -la'" } , true , ` "sh -c 'ls -la'" ` , commandHeader , ctx . Command } ,
{ types . Container { Created : unix } , true , time . Unix ( unix , 0 ) . String ( ) , createdAtHeader , ctx . CreatedAt } ,
{ types . Container { Ports : [ ] types . Port { { PrivatePort : 8080 , PublicPort : 8080 , Type : "tcp" } } } , true , "8080/tcp" , portsHeader , ctx . Ports } ,
{ types . Container { Status : "RUNNING" } , true , "RUNNING" , statusHeader , ctx . Status } ,
{ types . Container { SizeRw : 10 } , true , "10 B" , sizeHeader , ctx . Size } ,
{ types . Container { SizeRw : 10 , SizeRootFs : 20 } , true , "10 B (virtual 20 B)" , sizeHeader , ctx . Size } ,
{ types . Container { } , true , "" , labelsHeader , ctx . Labels } ,
{ types . Container { Labels : map [ string ] string { "cpu" : "6" , "storage" : "ssd" } } , true , "cpu=6,storage=ssd" , labelsHeader , ctx . Labels } ,
{ types . Container { Created : unix } , true , "About a minute" , runningForHeader , ctx . RunningFor } ,
{ types . Container {
Mounts : [ ] types . MountPoint {
{
Name : "this-is-a-long-volume-name-and-will-be-truncated-if-trunc-is-set" ,
Driver : "local" ,
Source : "/a/path" ,
} ,
} ,
} , true , "this-is-a-lo..." , mountsHeader , ctx . Mounts } ,
{ types . Container {
Mounts : [ ] types . MountPoint {
{
Driver : "local" ,
Source : "/a/path" ,
} ,
} ,
} , false , "/a/path" , mountsHeader , ctx . Mounts } ,
{ types . Container {
Mounts : [ ] types . MountPoint {
{
Name : "733908409c91817de8e92b0096373245f329f19a88e2c849f02460e9b3d1c203" ,
Driver : "local" ,
Source : "/a/path" ,
} ,
} ,
} , false , "733908409c91817de8e92b0096373245f329f19a88e2c849f02460e9b3d1c203" , mountsHeader , ctx . Mounts } ,
}
for _ , c := range cases {
ctx = containerContext { c : c . container , trunc : c . trunc }
v := c . call ( )
if strings . Contains ( v , "," ) {
compareMultipleValues ( t , v , c . expValue )
} else if v != c . expValue {
t . Fatalf ( "Expected %s, was %s\n" , c . expValue , v )
}
2016-09-12 16:59:18 -04:00
h := ctx . FullHeader ( )
2016-09-08 13:11:39 -04:00
if h != c . expHeader {
t . Fatalf ( "Expected %s, was %s\n" , c . expHeader , h )
}
}
c1 := types . Container { Labels : map [ string ] string { "com.docker.swarm.swarm-id" : "33" , "com.docker.swarm.node_name" : "ubuntu" } }
ctx = containerContext { c : c1 , trunc : true }
sid := ctx . Label ( "com.docker.swarm.swarm-id" )
node := ctx . Label ( "com.docker.swarm.node_name" )
if sid != "33" {
t . Fatalf ( "Expected 33, was %s\n" , sid )
}
if node != "ubuntu" {
t . Fatalf ( "Expected ubuntu, was %s\n" , node )
}
2016-09-12 16:59:18 -04:00
h := ctx . FullHeader ( )
2016-09-08 13:11:39 -04:00
if h != "SWARM ID\tNODE NAME" {
t . Fatalf ( "Expected %s, was %s\n" , "SWARM ID\tNODE NAME" , h )
}
c2 := types . Container { }
ctx = containerContext { c : c2 , trunc : true }
label := ctx . Label ( "anything.really" )
if label != "" {
t . Fatalf ( "Expected an empty string, was %s" , label )
}
ctx = containerContext { c : c2 , trunc : true }
2016-09-12 16:59:18 -04:00
FullHeader := ctx . FullHeader ( )
if FullHeader != "" {
t . Fatalf ( "Expected FullHeader to be empty, was %s" , FullHeader )
2016-09-08 13:11:39 -04:00
}
}
func TestContainerContextWrite ( t * testing . T ) {
unixTime := time . Now ( ) . AddDate ( 0 , 0 , - 1 ) . Unix ( )
expectedTime := time . Unix ( unixTime , 0 ) . String ( )
2016-09-12 16:59:18 -04:00
cases := [ ] struct {
context Context
2016-09-08 13:11:39 -04:00
expected string
} {
// Errors
{
2016-09-12 16:59:18 -04:00
Context { Format : "{{InvalidFunction}}" } ,
2016-09-08 13:11:39 -04:00
` Template parsing error : template : : 1 : function "InvalidFunction" not defined
` ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : "{{nil}}" } ,
2016-09-08 13:11:39 -04:00
` Template parsing error : template : : 1 : 2 : executing "" at < nil > : nil is not a command
` ,
} ,
// Table Format
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "table" , false , true ) } ,
2016-09-08 13:11:39 -04:00
` CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
containerID1 ubuntu "" 24 hours ago foobar_baz 0 B
containerID2 ubuntu "" 24 hours ago foobar_bar 0 B
` ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "table" , false , false ) } ,
2016-09-08 13:11:39 -04:00
` CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
containerID1 ubuntu "" 24 hours ago foobar_baz
containerID2 ubuntu "" 24 hours ago foobar_bar
` ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "table {{.Image}}" , false , false ) } ,
2016-09-08 13:11:39 -04:00
"IMAGE\nubuntu\nubuntu\n" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "table {{.Image}}" , false , true ) } ,
2016-09-08 13:11:39 -04:00
"IMAGE\nubuntu\nubuntu\n" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "table {{.Image}}" , true , false ) } ,
2016-09-08 13:11:39 -04:00
"IMAGE\nubuntu\nubuntu\n" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "table" , true , false ) } ,
2016-09-08 13:11:39 -04:00
"containerID1\ncontainerID2\n" ,
} ,
// Raw Format
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "raw" , false , false ) } ,
2016-09-08 13:11:39 -04:00
fmt . Sprintf ( ` container_id : containerID1
image : ubuntu
command : ""
created_at : % s
2016-09-12 16:59:18 -04:00
status :
2016-09-08 13:11:39 -04:00
names : foobar_baz
2016-09-12 16:59:18 -04:00
labels :
ports :
2016-09-08 13:11:39 -04:00
container_id : containerID2
image : ubuntu
command : ""
created_at : % s
2016-09-12 16:59:18 -04:00
status :
2016-09-08 13:11:39 -04:00
names : foobar_bar
2016-09-12 16:59:18 -04:00
labels :
ports :
2016-09-08 13:11:39 -04:00
` , expectedTime , expectedTime ) ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "raw" , false , true ) } ,
2016-09-08 13:11:39 -04:00
fmt . Sprintf ( ` container_id : containerID1
image : ubuntu
command : ""
created_at : % s
2016-09-12 16:59:18 -04:00
status :
2016-09-08 13:11:39 -04:00
names : foobar_baz
2016-09-12 16:59:18 -04:00
labels :
ports :
2016-09-08 13:11:39 -04:00
size : 0 B
container_id : containerID2
image : ubuntu
command : ""
created_at : % s
2016-09-12 16:59:18 -04:00
status :
2016-09-08 13:11:39 -04:00
names : foobar_bar
2016-09-12 16:59:18 -04:00
labels :
ports :
2016-09-08 13:11:39 -04:00
size : 0 B
` , expectedTime , expectedTime ) ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "raw" , true , false ) } ,
2016-09-08 13:11:39 -04:00
"container_id: containerID1\ncontainer_id: containerID2\n" ,
} ,
// Custom Format
{
2016-09-12 16:59:18 -04:00
Context { Format : "{{.Image}}" } ,
2016-09-08 13:11:39 -04:00
"ubuntu\nubuntu\n" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context { Format : NewContainerFormat ( "{{.Image}}" , false , true ) } ,
2016-09-08 13:11:39 -04:00
"ubuntu\nubuntu\n" ,
} ,
}
2016-09-12 16:59:18 -04:00
for _ , testcase := range cases {
2016-09-08 13:11:39 -04:00
containers := [ ] types . Container {
{ ID : "containerID1" , Names : [ ] string { "/foobar_baz" } , Image : "ubuntu" , Created : unixTime } ,
{ ID : "containerID2" , Names : [ ] string { "/foobar_bar" } , Image : "ubuntu" , Created : unixTime } ,
}
out := bytes . NewBufferString ( "" )
2016-09-12 16:59:18 -04:00
testcase . context . Output = out
err := ContainerWrite ( testcase . context , containers )
if err != nil {
assert . Error ( t , err , testcase . expected )
} else {
assert . Equal ( t , out . String ( ) , testcase . expected )
}
2016-09-08 13:11:39 -04:00
}
}
func TestContainerContextWriteWithNoContainers ( t * testing . T ) {
out := bytes . NewBufferString ( "" )
containers := [ ] types . Container { }
contexts := [ ] struct {
2016-09-12 16:59:18 -04:00
context Context
2016-09-08 13:11:39 -04:00
expected string
} {
{
2016-09-12 16:59:18 -04:00
Context {
Format : "{{.Image}}" ,
Output : out ,
2016-09-08 13:11:39 -04:00
} ,
"" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context {
Format : "table {{.Image}}" ,
Output : out ,
2016-09-08 13:11:39 -04:00
} ,
"IMAGE\n" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context {
Format : NewContainerFormat ( "{{.Image}}" , false , true ) ,
Output : out ,
2016-09-08 13:11:39 -04:00
} ,
"" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context {
Format : NewContainerFormat ( "table {{.Image}}" , false , true ) ,
Output : out ,
2016-09-08 13:11:39 -04:00
} ,
"IMAGE\n" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context {
Format : "table {{.Image}}\t{{.Size}}" ,
Output : out ,
2016-09-08 13:11:39 -04:00
} ,
"IMAGE SIZE\n" ,
} ,
{
2016-09-12 16:59:18 -04:00
Context {
Format : NewContainerFormat ( "table {{.Image}}\t{{.Size}}" , false , true ) ,
Output : out ,
2016-09-08 13:11:39 -04:00
} ,
"IMAGE SIZE\n" ,
} ,
}
for _ , context := range contexts {
2016-09-12 16:59:18 -04:00
ContainerWrite ( context . context , containers )
assert . Equal ( t , context . expected , out . String ( ) )
2016-09-08 13:11:39 -04:00
// Clean buffer
out . Reset ( )
}
}
2016-09-13 03:01:31 -04:00
func TestContainerContextWriteJSON ( t * testing . T ) {
unix := time . Now ( ) . Add ( - 65 * time . Second ) . Unix ( )
containers := [ ] types . Container {
{ ID : "containerID1" , Names : [ ] string { "/foobar_baz" } , Image : "ubuntu" , Created : unix } ,
{ ID : "containerID2" , Names : [ ] string { "/foobar_bar" } , Image : "ubuntu" , Created : unix } ,
}
expectedCreated := time . Unix ( unix , 0 ) . String ( )
expectedJSONs := [ ] map [ string ] interface { } {
2016-10-19 18:09:42 -04:00
{ "Command" : "\"\"" , "CreatedAt" : expectedCreated , "ID" : "containerID1" , "Image" : "ubuntu" , "Labels" : "" , "LocalVolumes" : "0" , "Mounts" : "" , "Names" : "foobar_baz" , "Networks" : "" , "Ports" : "" , "RunningFor" : "About a minute" , "Size" : "0 B" , "Status" : "" } ,
{ "Command" : "\"\"" , "CreatedAt" : expectedCreated , "ID" : "containerID2" , "Image" : "ubuntu" , "Labels" : "" , "LocalVolumes" : "0" , "Mounts" : "" , "Names" : "foobar_bar" , "Networks" : "" , "Ports" : "" , "RunningFor" : "About a minute" , "Size" : "0 B" , "Status" : "" } ,
2016-09-13 03:01:31 -04:00
}
out := bytes . NewBufferString ( "" )
err := ContainerWrite ( Context { Format : "{{json .}}" , Output : out } , containers )
if err != nil {
t . Fatal ( err )
}
for i , line := range strings . Split ( strings . TrimSpace ( out . String ( ) ) , "\n" ) {
t . Logf ( "Output: line %d: %s" , i , line )
var m map [ string ] interface { }
if err := json . Unmarshal ( [ ] byte ( line ) , & m ) ; err != nil {
t . Fatal ( err )
}
assert . DeepEqual ( t , m , expectedJSONs [ i ] )
}
}
func TestContainerContextWriteJSONField ( t * testing . T ) {
containers := [ ] types . Container {
{ ID : "containerID1" , Names : [ ] string { "/foobar_baz" } , Image : "ubuntu" } ,
{ ID : "containerID2" , Names : [ ] string { "/foobar_bar" } , Image : "ubuntu" } ,
}
out := bytes . NewBufferString ( "" )
err := ContainerWrite ( Context { Format : "{{json .ID}}" , Output : out } , containers )
if err != nil {
t . Fatal ( err )
}
for i , line := range strings . Split ( strings . TrimSpace ( out . String ( ) ) , "\n" ) {
t . Logf ( "Output: line %d: %s" , i , line )
var s string
if err := json . Unmarshal ( [ ] byte ( line ) , & s ) ; err != nil {
t . Fatal ( err )
}
assert . Equal ( t , s , containers [ i ] . ID )
}
}