{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}
module Types.HostSpec where
import Control.Monad (forM_)
import Data.Aeson (decode, encode, Value(..))
import Data.Aeson.QQ
import Data.Default
import qualified Data.HashMap.Lazy as HM
import Test.Hspec
import Web.Mackerel.Types.Host
spec :: Spec
spec = do
let host1 = Host {
hostId = HostId "abcede",
hostName = "foohost.example",
hostDisplayName = Nothing,
hostStatus = HostStatusWorking,
hostMemo = "",
hostRoles = HM.fromList [],
hostIsRetired = False,
hostCreatedAt = 1483196400,
hostMeta = def,
hostInterfaces = []
}
let json1 = [aesonQQ|
{
"id": "abcede",
"name": "foohost.example",
"status": "working",
"memo": "",
"roles": {},
"isRetired": false,
"createdAt": 1483196400,
"meta": {},
"interfaces": []
}
|]
let host2 = Host {
hostId = HostId "abcede",
hostName = "foohost.example",
hostDisplayName = Just "Host Foo",
hostStatus = HostStatusWorking,
hostMemo = "host memo",
hostRoles = HM.fromList [("foo", ["bar", "baz"]), ("qux", ["quux"])],
hostIsRetired = False,
hostCreatedAt = 1483196400,
hostMeta = def {
metaAgentName = Just "mackerel-agent/0.37.0 (Revision 3c11c2c)",
metaAgentRevision = Just "3c11c2c",
metaAgentVersion = Just "0.37.0",
metaBlockDevice = Just $ HM.fromList [
("xvda", HM.fromList [
("removable", "0"),
("size", "251658240")
])
],
metaCpu = Just [
HostMetaCpu {
metaCpuCacheSize = Just "25600 KB",
metaCpuCoreId = Just "0",
metaCpuCores = Just "1",
metaCpuFamily = Just "6",
metaCpuMhz = Just "2500.064",
metaCpuModel = Just "62",
metaCpuModelName = Just "Intel(R) Xeon(R) CPU E5-2670 v2 @ 2.50GHz",
metaCpuPhysicalId = Just "0",
metaCpuStepping = Just "4",
metaCpuVendorId = Just "GenuineIntel"
}
],
metaFilesystem = Just $ HM.fromList [
("/dev/xvda", HM.fromList [
("kb_available", Number $ read "2526784"),
("kb_size", Number $ read "8125880"),
("kb_used", Number $ read "5163284"),
("mount", "/"),
("percent_used", "68%")
])
],
metaKernel = Just $ HM.fromList [
("machine", "x86_64"),
("name", "Linux"),
("os", "GNU/Linux"),
("platform_name", "Debian"),
("platform_version", "8.3"),
("release", "3.16.0-4-amd64"),
("version", "#1 SMP Debian 3.16.7-ckt20-1+deb8u3 (2016-01-17)")
],
metaMemory = Just $ HM.fromList [
("active", "77456kB"),
("buffers", "11720kB"),
("cached", "83456kB"),
("free", "3685992kB"),
("inactive", "59368kB"),
("total", "3865572kB")
],
metaCloud = Just HostMetaCloud {
metaCloudProvider = "ec2",
metaCloudMetadata = HM.fromList [
("ami-id", "ami-000"),
("hostname", "ip-0-0-0-0"),
("instance-id", "i-00000"),
("instance-type", "m3.medium")
]
}
},
hostInterfaces = [
HostInterface {
hostInterfaceName = "en0",
hostInterfaceMacAddress = Just "ff:ff:ff:ff:ff:ff",
hostInterfaceIpv4Addresses = Just ["192.168.100.2"],
hostInterfaceIpv6Addresses = Just ["2001:268:c00f:8a08::"]
}
]
}
let json2 = [aesonQQ|
{
"id": "abcede",
"name": "foohost.example",
"displayName": "Host Foo",
"status": "working",
"memo": "host memo",
"roles": {
"foo": ["bar", "baz"],
"qux": ["quux"]
},
"isRetired": false,
"createdAt": 1483196400,
"meta": {
"agent-name": "mackerel-agent/0.37.0 (Revision 3c11c2c)",
"agent-revision": "3c11c2c",
"agent-version": "0.37.0",
"block_device": {
"xvda": {
"removable": "0",
"size": "251658240"
}
},
"cpu": [
{
"cache_size": "25600 KB",
"core_id": "0",
"cores": "1",
"family": "6",
"mhz": "2500.064",
"model": "62",
"model_name": "Intel(R) Xeon(R) CPU E5-2670 v2 @ 2.50GHz",
"physical_id": "0",
"stepping": "4",
"vendor_id": "GenuineIntel"
}
],
"filesystem": {
"/dev/xvda": {
"kb_available": 2526784,
"kb_size": 8125880,
"kb_used": 5163284,
"mount": "/",
"percent_used": "68%"
}
},
"kernel": {
"machine": "x86_64",
"name": "Linux",
"os": "GNU/Linux",
"platform_name": "Debian",
"platform_version": "8.3",
"release": "3.16.0-4-amd64",
"version": "#1 SMP Debian 3.16.7-ckt20-1+deb8u3 (2016-01-17)"
},
"memory": {
"active": "77456kB",
"buffers": "11720kB",
"cached": "83456kB",
"free": "3685992kB",
"inactive": "59368kB",
"total": "3865572kB"
},
"cloud": {
"provider": "ec2",
"metadata": {
"ami-id": "ami-000",
"hostname": "ip-0-0-0-0",
"instance-id": "i-00000",
"instance-type": "m3.medium"
}
}
},
"interfaces": [
{
"name": "en0",
"macAddress": "ff:ff:ff:ff:ff:ff",
"ipv4Addresses": ["192.168.100.2"],
"ipv6Addresses": ["2001:268:c00f:8a08::"]
}
]
}
|]
describe "Host FromJSON" $ do
it "should parse a json" $
forM_ [(json1, host1), (json2, host2)] $ \(json, host) ->
decode (encode json) `shouldBe` Just host
it "should reject an invalid json" $ do
decode "{}" `shouldBe` (Nothing :: Maybe Host)
let (Object hm) = json1
forM_ ["id", "name", "status", "memo", "roles", "isRetired", "createdAt", "meta", "interfaces"] $ \key ->
decode (encode (Object (HM.delete key hm))) `shouldBe` (Nothing :: Maybe Host)
forM_ ["status", "roles", "isRetired", "createdAt", "meta", "interfaces"] $ \key ->
decode (encode (Object (HM.insert key "invalid" hm))) `shouldBe` (Nothing :: Maybe Host)
describe "Host ToJSON" $
it "should encode into a json" $
forM_ [(json1, host1), (json2, host2)] $ \(json, host) ->
decode (encode host) `shouldBe` Just json
describe "HostStatus Show" $
it "should show properly" $ do
show HostStatusWorking `shouldBe` "working"
show HostStatusMaintenance `shouldBe` "maintenance"
show [HostStatusWorking, HostStatusStandby, HostStatusMaintenance, HostStatusPoweroff] `shouldBe` "[working,standby,maintenance,poweroff]"
describe "HostStatus Read" $
it "should read properly" $ do
read "working" `shouldBe` HostStatusWorking
read "maintenance" `shouldBe` HostStatusMaintenance
read "[working,standby,maintenance,poweroff]" `shouldBe` [HostStatusWorking, HostStatusStandby, HostStatusMaintenance, HostStatusPoweroff]
let hostCreate1 = HostCreate {
hostCreateName = "foohost.example",
hostCreateDisplayName = Nothing,
hostCreateCustomIdentifier = Nothing,
hostCreateMeta = def,
hostCreateInterfaces = Nothing,
hostCreateRoleFullnames = Nothing,
hostCreateChecks = Nothing
}
let jsonCreate1 = [aesonQQ|
{
"name": "foohost.example",
"meta": {}
}
|]
let hostCreate2 = HostCreate {
hostCreateName = "foohost.example",
hostCreateDisplayName = Just "Foo host",
hostCreateCustomIdentifier = Just "foo-host-identifier",
hostCreateMeta = def {
metaAgentName = Just "mackerel-agent/0.37.0 (Revision 3c11c2c)",
metaAgentRevision = Just "3c11c2c",
metaAgentVersion = Just "0.37.0"
},
hostCreateInterfaces = Just [
HostInterface {
hostInterfaceName = "en0",
hostInterfaceMacAddress = Just "ff:ff:ff:ff:ff:ff",
hostInterfaceIpv4Addresses = Just ["192.168.100.2"],
hostInterfaceIpv6Addresses = Just ["2001:268:c00f:8a08::"]
}
],
hostCreateRoleFullnames = Just ["foo:bar", "foo:baz"],
hostCreateChecks = Just [
"plugin.checks.access_log",
"plugin.checks.check_cron"
]
}
let jsonCreate2 = [aesonQQ|
{
"name": "foohost.example",
"displayName": "Foo host",
"customIdentifier": "foo-host-identifier",
"meta": {
"agent-name": "mackerel-agent/0.37.0 (Revision 3c11c2c)",
"agent-revision": "3c11c2c",
"agent-version": "0.37.0"
},
"interfaces": [
{
"name": "en0",
"macAddress": "ff:ff:ff:ff:ff:ff",
"ipv4Addresses": ["192.168.100.2"],
"ipv6Addresses": ["2001:268:c00f:8a08::"]
}
],
"roleFullnames": [
"foo:bar",
"foo:baz"
],
"checks": [
"plugin.checks.access_log",
"plugin.checks.check_cron"
]
}
|]
describe "HostCreate FromJSON" $
it "should parse a json" $
forM_ [(jsonCreate1, hostCreate1), (jsonCreate2, hostCreate2)] $ \(json, host) ->
decode (encode json) `shouldBe` Just host
describe "HostCreate ToJSON" $
it "should encode into a json" $
forM_ [(jsonCreate1, hostCreate1), (jsonCreate2, hostCreate2)] $ \(json, host) ->
decode (encode host) `shouldBe` Just json